Blame SOURCES/nfs-utils-1.3.0-rpcgssd-debug.patch

e19a30
diff -up nfs-utils-1.3.0/aclocal/libtirpc.m4.orig nfs-utils-1.3.0/aclocal/libtirpc.m4
e19a30
--- nfs-utils-1.3.0/aclocal/libtirpc.m4.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/aclocal/libtirpc.m4	2016-04-15 11:42:49.532156526 -0400
e19a30
@@ -2,61 +2,61 @@ dnl Checks for TI-RPC library and header
e19a30
 dnl
e19a30
 AC_DEFUN([AC_LIBTIRPC], [
e19a30
 
e19a30
+  AS_IF(
e19a30
+    [test "$enable_tirpc" != "no"],
e19a30
+    [PKG_CHECK_MODULES([TIRPC], [libtirpc],
e19a30
+                      [LIBTIRPC="${TIRPC_LIBS}"
e19a30
+                       AM_CPPFLAGS="${AM_CPPFLAGS} ${TIRPC_CFLAGS}"
e19a30
+                       AC_DEFINE([HAVE_LIBTIRPC], [1],
e19a30
+                                 [Define to 1 if you have and wish to use libtirpc.])],
e19a30
+                      [AC_LIBTIRPC_OLD
e19a30
+                       AS_IF([test "$enable_tirpc" = "yes" -a -z "${LIBTIRPC}"],
e19a30
+                             [AC_MSG_ERROR([libtirpc not found.])])])])
e19a30
+
e19a30
+     AS_IF([test -n "${LIBTIRPC}"],
e19a30
+           [AC_CHECK_LIB([tirpc], [authgss_free_private_data],
e19a30
+                         [AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], [1],
e19a30
+                                    [Define to 1 if your rpcsec library provides authgss_free_private_data])],,
e19a30
+                         [${LIBS}])])
e19a30
+
e19a30
+     AS_IF([test -n "${LIBTIRPC}"],
e19a30
+           [AC_CHECK_LIB([tirpc], [libtirpc_set_debug],
e19a30
+                         [AC_DEFINE([HAVE_LIBTIRPC_SET_DEBUG], [1],
e19a30
+                                    [Define to 1 if your tirpc library provides libtirpc_set_debug])],,
e19a30
+                         [${LIBS}])])
e19a30
+
e19a30
+  AC_SUBST([AM_CPPFLAGS])
e19a30
+  AC_SUBST(LIBTIRPC)
e19a30
+
e19a30
+])dnl
e19a30
+
e19a30
+dnl Old way of checking libtirpc without pkg-config
e19a30
+dnl This can go away when virtually all libtirpc provide a .pc file
e19a30
+dnl
e19a30
+AC_DEFUN([AC_LIBTIRPC_OLD], [
e19a30
+
e19a30
   AC_ARG_WITH([tirpcinclude],
e19a30
               [AC_HELP_STRING([--with-tirpcinclude=DIR],
e19a30
                               [use TI-RPC headers in DIR])],
e19a30
               [tirpc_header_dir=$withval],
e19a30
               [tirpc_header_dir=/usr/include/tirpc])
e19a30
 
e19a30
-  dnl if --enable-tirpc was specifed, the following components
e19a30
-  dnl must be present, and we set up HAVE_ macros for them.
e19a30
-
e19a30
-  if test "$enable_tirpc" != "no"; then
e19a30
-
e19a30
-    dnl look for the library
e19a30
-    AC_CHECK_LIB([tirpc], [clnt_tli_create], [:],
e19a30
-                 [if test "$enable_tirpc" = "yes"; then
e19a30
-			AC_MSG_ERROR([libtirpc not found.])
e19a30
-		  else
e19a30
-			AC_MSG_WARN([libtirpc not found. TIRPC disabled!])
e19a30
-			enable_tirpc="no"
e19a30
-		  fi])
e19a30
-  fi
e19a30
-
e19a30
-  if test "$enable_tirpc" != "no"; then
e19a30
-
e19a30
-    dnl Check if library contains authgss_free_private_data
e19a30
-    AC_CHECK_LIB([tirpc], [authgss_free_private_data], [have_free_private_data=yes],
e19a30
-			[have_free_private_data=no])
e19a30
-  fi
e19a30
-
e19a30
-  if test "$enable_tirpc" != "no"; then
e19a30
-    dnl also must have the headers installed where we expect
e19a30
-    dnl look for headers; add -I compiler option if found
e19a30
-    AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h],
e19a30
-    		      AC_SUBST([AM_CPPFLAGS], ["-I${tirpc_header_dir}"]),
e19a30
-		      [if test "$enable_tirpc" = "yes"; then
e19a30
-			 AC_MSG_ERROR([libtirpc headers not found.])
e19a30
-		       else
e19a30
-			 AC_MSG_WARN([libtirpc headers not found. TIRPC disabled!])
e19a30
-			 enable_tirpc="no"
e19a30
-		       fi])
e19a30
-
e19a30
-  fi
e19a30
-
e19a30
-  dnl now set $LIBTIRPC accordingly
e19a30
-  if test "$enable_tirpc" != "no"; then
e19a30
-    AC_DEFINE([HAVE_LIBTIRPC], 1,
e19a30
-              [Define to 1 if you have and wish to use libtirpc.])
e19a30
-    LIBTIRPC="-ltirpc"
e19a30
-    if test "$have_free_private_data" = "yes"; then
e19a30
-      AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1,
e19a30
-	      [Define to 1 if your rpcsec library provides authgss_free_private_data,])
e19a30
-    fi
e19a30
-  else
e19a30
-    LIBTIRPC=""
e19a30
-  fi
e19a30
-
e19a30
-  AC_SUBST(LIBTIRPC)
e19a30
+  dnl Look for the library
e19a30
+  AC_CHECK_LIB([tirpc], [clnt_tli_create],
e19a30
+               [has_libtirpc="yes"],
e19a30
+               [has_libtirpc="no"])
e19a30
+
e19a30
+  dnl Also must have the headers installed where we expect
e19a30
+  dnl to look for headers; add -I compiler option if found
e19a30
+  AS_IF([test "$has_libtirpc" = "yes"],
e19a30
+        [AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h],
e19a30
+                          [AC_SUBST([AM_CPPFLAGS], ["-I${tirpc_header_dir}"])],
e19a30
+                          [has_libtirpc="no"])])
e19a30
+
e19a30
+  dnl Now set $LIBTIRPC accordingly
e19a30
+  AS_IF([test "$has_libtirpc" = "yes"],
e19a30
+        [AC_DEFINE([HAVE_LIBTIRPC], [1],
e19a30
+                   [Define to 1 if you have and wish to use libtirpc.])
e19a30
+         LIBTIRPC="-ltirpc"])
e19a30
 
e19a30
 ])dnl
e19a30
diff -up nfs-utils-1.3.0/support/include/nfslib.h.orig nfs-utils-1.3.0/support/include/nfslib.h
e19a30
--- nfs-utils-1.3.0/support/include/nfslib.h.orig	2016-04-15 11:42:13.930460892 -0400
e19a30
+++ nfs-utils-1.3.0/support/include/nfslib.h	2016-04-15 11:42:38.365938345 -0400
e19a30
@@ -17,6 +17,7 @@
e19a30
 #include <sys/socket.h>
e19a30
 #include <netinet/in.h>
e19a30
 #include <stdio.h>
e19a30
+#include <stdbool.h>
e19a30
 #include <paths.h>
e19a30
 #include <rpcsvc/nfs_prot.h>
e19a30
 #include <nfs/nfs.h>
e19a30
@@ -129,8 +130,8 @@ void			fendrmtabent(FILE *fp);
e19a30
 void			frewindrmtabent(FILE *fp);
e19a30
 
e19a30
 /* mydaemon */
e19a30
-void mydaemon(int nochdir, int noclose, int *pipefds);
e19a30
-void release_parent(int *pipefds);
e19a30
+void daemon_init(bool fg);
e19a30
+void daemon_ready(void);
e19a30
 
e19a30
 /*
e19a30
  * wildmat borrowed from INN
e19a30
@@ -182,6 +183,9 @@ size_t  strlcpy(char *, const char *, si
e19a30
 ssize_t atomicio(ssize_t (*f) (int, void*, size_t),
e19a30
 		 int, void *, size_t);
e19a30
 
e19a30
+#ifdef HAVE_LIBTIRPC_SET_DEBUG
e19a30
+void  libtirpc_set_debug(char *name, int level, int use_stderr);
e19a30
+#endif
e19a30
 
e19a30
 #define UNUSED(x) UNUSED_ ## x __attribute__((unused))
e19a30
 
e19a30
diff -up nfs-utils-1.3.0/support/nfs/mydaemon.c.orig nfs-utils-1.3.0/support/nfs/mydaemon.c
e19a30
--- nfs-utils-1.3.0/support/nfs/mydaemon.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/support/nfs/mydaemon.c	2016-04-15 11:42:38.366938365 -0400
e19a30
@@ -46,56 +46,61 @@
e19a30
 #include <errno.h>
e19a30
 #include <unistd.h>
e19a30
 #include <stdio.h>
e19a30
+#include <stdbool.h>
e19a30
 #include <stdlib.h>
e19a30
 #include <string.h>
e19a30
 #include <xlog.h>
e19a30
 
e19a30
+#include "nfslib.h"
e19a30
+
e19a30
+static int pipefds[2] = { -1, -1};
e19a30
+
e19a30
 /**
e19a30
- * mydaemon - daemonize, but have parent wait to exit
e19a30
- * @nochdir:	skip chdir()'ing the child to / after forking if true
e19a30
- * @noclose:	skip closing stdin/stdout/stderr if true
e19a30
- * @pipefds:	pointer to 2 element array of pipefds
e19a30
+ * daemon_init - initial daemon setup
e19a30
+ * @fg:		whether to run in the foreground
e19a30
  *
e19a30
  * This function is like daemon(), but with our own special sauce to delay
e19a30
  * the exit of the parent until the child is set up properly. A pipe is created
e19a30
  * between parent and child. The parent process will wait to exit until the
e19a30
- * child dies or writes a '1' on the pipe signaling that it started
e19a30
- * successfully.
e19a30
+ * child dies or writes an int on the pipe signaling its status.
e19a30
  */
e19a30
 void
e19a30
-mydaemon(int nochdir, int noclose, int *pipefds)
e19a30
+daemon_init(bool fg)
e19a30
 {
e19a30
 	int pid, status, tempfd;
e19a30
 
e19a30
+	if (fg)
e19a30
+		return;
e19a30
+
e19a30
 	if (pipe(pipefds) < 0) {
e19a30
 		xlog_err("mydaemon: pipe() failed: errno %d (%s)\n",
e19a30
 			 errno, strerror(errno));
e19a30
-		exit(1);
e19a30
+		exit(EXIT_FAILURE);
e19a30
 	}
e19a30
-	if ((pid = fork ()) < 0) {
e19a30
+
e19a30
+	pid = fork();
e19a30
+	if (pid < 0) {
e19a30
 		xlog_err("mydaemon: fork() failed: errno %d (%s)\n",
e19a30
 			 errno, strerror(errno));
e19a30
-		exit(1);
e19a30
+		exit(EXIT_FAILURE);
e19a30
 	}
e19a30
 
e19a30
-	if (pid != 0) {
e19a30
-		/*
e19a30
-		 * Parent. Wait for status from child.
e19a30
-		 */
e19a30
+	if (pid > 0) {
e19a30
+		/* Parent */
e19a30
 		close(pipefds[1]);
e19a30
-		if (read(pipefds[0], &status, 1) != 1)
e19a30
-			exit(1);
e19a30
-		exit (0);
e19a30
+		if (read(pipefds[0], &status, sizeof(status)) != sizeof(status))
e19a30
+			exit(EXIT_FAILURE);
e19a30
+		exit(status);
e19a30
 	}
e19a30
-	/* Child.	*/
e19a30
+
e19a30
+	/* Child */
e19a30
 	close(pipefds[0]);
e19a30
 	setsid ();
e19a30
-	if (nochdir == 0) {
e19a30
-		if (chdir ("/") == -1) {
e19a30
-			xlog_err("mydaemon: chdir() failed: errno %d (%s)\n",
e19a30
-				 errno, strerror(errno));
e19a30
-			exit(1);
e19a30
-		}
e19a30
+
e19a30
+	if (chdir ("/")) {
e19a30
+		xlog_err("mydaemon: chdir() failed: errno %d (%s)\n",
e19a30
+			 errno, strerror(errno));
e19a30
+		exit(EXIT_FAILURE);
e19a30
 	}
e19a30
 
e19a30
 	while (pipefds[1] <= 2) {
e19a30
@@ -103,41 +108,39 @@ mydaemon(int nochdir, int noclose, int *
e19a30
 		if (pipefds[1] < 0) {
e19a30
 			xlog_err("mydaemon: dup() failed: errno %d (%s)\n",
e19a30
 				 errno, strerror(errno));
e19a30
-			exit(1);
e19a30
+			exit(EXIT_FAILURE);
e19a30
 		}
e19a30
 	}
e19a30
 
e19a30
-	if (noclose == 0) {
e19a30
-		tempfd = open("/dev/null", O_RDWR);
e19a30
-		if (tempfd >= 0) {
e19a30
-			dup2(tempfd, 0);
e19a30
-			dup2(tempfd, 1);
e19a30
-			dup2(tempfd, 2);
e19a30
-			close(tempfd);
e19a30
-		} else {
e19a30
-			xlog_err("mydaemon: can't open /dev/null: errno %d "
e19a30
-				 "(%s)\n", errno, strerror(errno));
e19a30
-			exit(1);
e19a30
-		}
e19a30
+	tempfd = open("/dev/null", O_RDWR);
e19a30
+	if (tempfd < 0) {
e19a30
+		xlog_err("mydaemon: can't open /dev/null: errno %d "
e19a30
+			 "(%s)\n", errno, strerror(errno));
e19a30
+		exit(EXIT_FAILURE);
e19a30
 	}
e19a30
 
e19a30
-	return;
e19a30
+	dup2(tempfd, 0);
e19a30
+	dup2(tempfd, 1);
e19a30
+	dup2(tempfd, 2);
e19a30
+	closelog();
e19a30
+	dup2(pipefds[1], 3);
e19a30
+	pipefds[1] = 3;
e19a30
+	closeall(4);
e19a30
 }
e19a30
 
e19a30
 /**
e19a30
- * release_parent - tell the parent that it can exit now
e19a30
- * @pipefds:	pipefd array that was previously passed to mydaemon()
e19a30
+ * daemon_ready - tell interested parties that the daemon is ready
e19a30
  *
e19a30
- * This function tells the parent process of mydaemon() that it's now clear
e19a30
- * to exit(0).
e19a30
+ * This function tells e.g. the parent process that the daemon is up
e19a30
+ * and running.
e19a30
  */
e19a30
 void
e19a30
-release_parent(int *pipefds)
e19a30
+daemon_ready(void)
e19a30
 {
e19a30
-	int status;
e19a30
+	int status = 0;
e19a30
 
e19a30
 	if (pipefds[1] > 0) {
e19a30
-		if (write(pipefds[1], &status, 1) != 1) {
e19a30
+		if (write(pipefds[1], &status, sizeof(status)) != sizeof(status)) {
e19a30
 			xlog_err("WARN: writing to parent pipe failed: errno "
e19a30
 				 "%d (%s)\n", errno, strerror(errno));
e19a30
 		}
e19a30
diff -up nfs-utils-1.3.0/support/nfs/svc_create.c.orig nfs-utils-1.3.0/support/nfs/svc_create.c
e19a30
--- nfs-utils-1.3.0/support/nfs/svc_create.c.orig	2016-04-15 11:42:13.931460911 -0400
e19a30
+++ nfs-utils-1.3.0/support/nfs/svc_create.c	2016-04-15 11:42:38.366938365 -0400
e19a30
@@ -133,7 +133,7 @@ svc_create_bindaddr(struct netconfig *nc
e19a30
 		hint.ai_family = AF_INET6;
e19a30
 #endif	/* IPV6_SUPPORTED */
e19a30
 	else {
e19a30
-		xlog(D_GENERAL, "Unrecognized bind address family: %s",
e19a30
+		xlog(L_ERROR, "Unrecognized bind address family: %s",
e19a30
 			nconf->nc_protofmly);
e19a30
 		return NULL;
e19a30
 	}
e19a30
@@ -143,7 +143,7 @@ svc_create_bindaddr(struct netconfig *nc
e19a30
 	else if (strcmp(nconf->nc_proto, NC_TCP) == 0)
e19a30
 		hint.ai_protocol = (int)IPPROTO_TCP;
e19a30
 	else {
e19a30
-		xlog(D_GENERAL, "Unrecognized bind address protocol: %s",
e19a30
+		xlog(L_ERROR, "Unrecognized bind address protocol: %s",
e19a30
 			nconf->nc_proto);
e19a30
 		return NULL;
e19a30
 	}
e19a30
@@ -275,7 +275,7 @@ svc_create_nconf_rand_port(const char *n
e19a30
 	xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0);
e19a30
 	freeaddrinfo(ai);
e19a30
 	if (xprt == NULL) {
e19a30
-		xlog(D_GENERAL, "Failed to create listener xprt "
e19a30
+		xlog(L_ERROR, "Failed to create listener xprt "
e19a30
 			"(%s, %u, %s)", name, version, nconf->nc_netid);
e19a30
 		return 0;
e19a30
 	}
e19a30
@@ -286,10 +286,12 @@ svc_create_nconf_rand_port(const char *n
e19a30
 		return 0;
e19a30
 	}
e19a30
 
e19a30
+	rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0;
e19a30
 	if (!svc_reg(xprt, program, version, dispatch, nconf)) {
e19a30
 		/* svc_reg(3) destroys @xprt in this case */
e19a30
-		xlog(D_GENERAL, "Failed to register (%s, %u, %s)",
e19a30
-				name, version, nconf->nc_netid);
e19a30
+		xlog(L_ERROR, "Failed to register (%s, %u, %s): %s",
e19a30
+				name, version, nconf->nc_netid, 
e19a30
+				clnt_spcreateerror("svc_reg() err"));
e19a30
 		return 0;
e19a30
 	}
e19a30
 
e19a30
diff -up nfs-utils-1.3.0/support/nfs/svc_socket.c.orig nfs-utils-1.3.0/support/nfs/svc_socket.c
e19a30
--- nfs-utils-1.3.0/support/nfs/svc_socket.c.orig	2016-04-15 11:42:13.931460911 -0400
e19a30
+++ nfs-utils-1.3.0/support/nfs/svc_socket.c	2016-04-15 11:42:38.367938385 -0400
e19a30
@@ -24,6 +24,7 @@
e19a30
 #include <sys/socket.h>
e19a30
 #include <sys/fcntl.h>
e19a30
 #include <errno.h>
e19a30
+#include "xlog.h"
e19a30
 
e19a30
 #ifdef _LIBC
e19a30
 # include <libintl.h>
e19a30
@@ -90,9 +91,9 @@ svcsock_nonblock(int sock)
e19a30
 	 * connection.
e19a30
 	 */
e19a30
 	if ((flags = fcntl(sock, F_GETFL)) < 0)
e19a30
-		perror(_("svc_socket: can't get socket flags"));
e19a30
+		xlog(L_ERROR, "svc_socket: can't get socket flags: %m");
e19a30
 	else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0)
e19a30
-		perror(_("svc_socket: can't set socket flags"));
e19a30
+		xlog(L_ERROR, "svc_socket: can't set socket flags: %m");
e19a30
 	else
e19a30
 		return sock;
e19a30
 
e19a30
@@ -110,7 +111,7 @@ svc_socket (u_long number, int type, int
e19a30
 
e19a30
   if ((sock = __socket (AF_INET, type, protocol)) < 0)
e19a30
     {
e19a30
-      perror (_("svc_socket: socket creation problem"));
e19a30
+      xlog(L_ERROR, "svc_socket: socket creation problem: %m");
e19a30
       return sock;
e19a30
     }
e19a30
 
e19a30
@@ -121,7 +122,7 @@ svc_socket (u_long number, int type, int
e19a30
 			sizeof (ret));
e19a30
       if (ret < 0)
e19a30
 	{
e19a30
-	  perror (_("svc_socket: socket reuse problem"));
e19a30
+	  xlog(L_ERROR, "svc_socket: socket reuse problem: %m");
e19a30
 	  return ret;
e19a30
 	}
e19a30
     }
e19a30
@@ -132,7 +133,7 @@ svc_socket (u_long number, int type, int
e19a30
 
e19a30
   if (bind(sock, (struct sockaddr *) &addr, len) < 0)
e19a30
     {
e19a30
-      perror (_("svc_socket: bind problem"));
e19a30
+      xlog(L_ERROR, "svc_socket: bind problem: %m");
e19a30
       (void) __close(sock);
e19a30
       sock = -1;
e19a30
     }
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/context_heimdal.c.orig nfs-utils-1.3.0/utils/gssd/context_heimdal.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/context_heimdal.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/context_heimdal.c	2016-04-15 11:42:38.367938385 -0400
e19a30
@@ -260,7 +260,7 @@ serialize_krb5_ctx(gss_ctx_id_t *_ctx, g
e19a30
 	if (write_heimdal_seq_key(&p, end, ctx)) goto out_err;
e19a30
 
e19a30
 	buf->length = p - (char *)buf->value;
e19a30
-	printerr(2, "serialize_krb5_ctx: returning buffer "
e19a30
+	printerr(4, "serialize_krb5_ctx: returning buffer "
e19a30
 		    "with %d bytes\n", buf->length);
e19a30
 
e19a30
 	return 0;
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/context_lucid.c.orig nfs-utils-1.3.0/utils/gssd/context_lucid.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/context_lucid.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/context_lucid.c	2016-04-15 11:42:38.367938385 -0400
e19a30
@@ -206,7 +206,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc
e19a30
 	if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
e19a30
 
e19a30
 	/* Protocol 0 here implies DES3 or RC4 */
e19a30
-	printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
e19a30
+	printerr(4, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
e19a30
 	if (lctx->protocol == 0) {
e19a30
 		enctype = lctx->rfc1964_kd.ctx_key.type;
e19a30
 		keysize = lctx->rfc1964_kd.ctx_key.length;
e19a30
@@ -219,7 +219,7 @@ prepare_krb5_rfc4121_buffer(gss_krb5_luc
e19a30
 			keysize = lctx->cfx_kd.ctx_key.length;
e19a30
 		}
e19a30
 	}
e19a30
-	printerr(2, "%s: serializing key with enctype %d and size %d\n",
e19a30
+	printerr(4, "%s: serializing key with enctype %d and size %d\n",
e19a30
 		 __FUNCTION__, enctype, keysize);
e19a30
 
e19a30
 	if (WRITE_BYTES(&p, end, enctype)) goto out_err;
e19a30
@@ -265,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t *ctx, gs
e19a30
 	gss_krb5_lucid_context_v1_t *lctx = 0;
e19a30
 	int retcode = 0;
e19a30
 
e19a30
-	printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
e19a30
+	printerr(4, "DEBUG: %s: lucid version!\n", __FUNCTION__);
e19a30
 	maj_stat = gss_export_lucid_sec_context(&min_stat, ctx,
e19a30
 						1, &return_ctx);
e19a30
 	if (maj_stat != GSS_S_COMPLETE) {
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/gssd.c.orig nfs-utils-1.3.0/utils/gssd/gssd.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/gssd.c.orig	2016-04-15 11:42:13.917460638 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/gssd.c	2016-04-15 11:42:38.369938424 -0400
e19a30
@@ -1,7 +1,7 @@
e19a30
 /*
e19a30
   gssd.c
e19a30
 
e19a30
-  Copyright (c) 2000 The Regents of the University of Michigan.
e19a30
+  Copyright (c) 2000, 2004 The Regents of the University of Michigan.
e19a30
   All rights reserved.
e19a30
 
e19a30
   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
e19a30
@@ -40,9 +40,18 @@
e19a30
 #include <config.h>
e19a30
 #endif	/* HAVE_CONFIG_H */
e19a30
 
e19a30
+#ifndef _GNU_SOURCE
e19a30
+#define _GNU_SOURCE
e19a30
+#endif
e19a30
+
e19a30
 #include <sys/param.h>
e19a30
 #include <sys/socket.h>
e19a30
+#include <sys/time.h>
e19a30
+#include <sys/resource.h>
e19a30
+#include <sys/inotify.h>
e19a30
 #include <rpc/rpc.h>
e19a30
+#include <netinet/in.h>
e19a30
+#include <arpa/inet.h>
e19a30
 
e19a30
 #include <unistd.h>
e19a30
 #include <err.h>
e19a30
@@ -51,41 +60,684 @@
e19a30
 #include <stdlib.h>
e19a30
 #include <string.h>
e19a30
 #include <signal.h>
e19a30
+#include <memory.h>
e19a30
+#include <fcntl.h>
e19a30
+#include <dirent.h>
e19a30
+#include <netdb.h>
e19a30
+#include <event.h>
e19a30
+
e19a30
 #include "gssd.h"
e19a30
 #include "err_util.h"
e19a30
 #include "gss_util.h"
e19a30
 #include "krb5_util.h"
e19a30
 #include "nfslib.h"
e19a30
 
e19a30
-char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
e19a30
-char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
e19a30
-char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR ":" GSSD_USER_CRED_DIR;
e19a30
-char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
e19a30
+static char *pipefs_path = GSSD_PIPEFS_DIR;
e19a30
+static DIR *pipefs_dir;
e19a30
+static int pipefs_fd;
e19a30
+static int inotify_fd;
e19a30
+struct event inotify_ev;
e19a30
+
e19a30
+char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE;
e19a30
+char **ccachesearch;
e19a30
 int  use_memcache = 0;
e19a30
 int  root_uses_machine_creds = 1;
e19a30
 unsigned int  context_timeout = 0;
e19a30
 unsigned int  rpc_timeout = 5;
e19a30
 char *preferred_realm = NULL;
e19a30
-int pipefds[2] = { -1, -1 };
e19a30
+/* Avoid DNS reverse lookups on server names */
e19a30
+static bool avoid_dns = true;
e19a30
+
e19a30
+
e19a30
+TAILQ_HEAD(topdir_list_head, topdir) topdir_list;
e19a30
+
e19a30
+struct topdir {
e19a30
+	TAILQ_ENTRY(topdir) list;
e19a30
+	TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
e19a30
+	int wd;
e19a30
+	char name[];
e19a30
+};
e19a30
+
e19a30
+/*
e19a30
+ * topdir_list:
e19a30
+ *	linked list of struct topdir with basic data about a topdir.
e19a30
+ *
e19a30
+ * clnt_list:
e19a30
+ *      linked list of struct clnt_info with basic data about a clntXXX dir,
e19a30
+ *      one per topdir.
e19a30
+ *
e19a30
+ * Directory structure: created by the kernel
e19a30
+ *      {rpc_pipefs}/{topdir}/clntXX      : one per rpc_clnt struct in the kernel
e19a30
+ *      {rpc_pipefs}/{topdir}/clntXX/krb5 : read uid for which kernel wants
e19a30
+ *					    a context, write the resulting context
e19a30
+ *      {rpc_pipefs}/{topdir}/clntXX/info : stores info such as server name
e19a30
+ *      {rpc_pipefs}/{topdir}/clntXX/gssd : pipe for all gss mechanisms using
e19a30
+ *					    a text-based string of parameters
e19a30
+ *
e19a30
+ * Algorithm:
e19a30
+ *      Poll all {rpc_pipefs}/{topdir}/clntXX/YYYY files.  When data is ready,
e19a30
+ *      read and process; performs rpcsec_gss context initialization protocol to
e19a30
+ *      get a cred for that user.  Writes result to corresponding krb5 file
e19a30
+ *      in a form the kernel code will understand.
e19a30
+ *      In addition, we make sure we are notified whenever anything is
e19a30
+ *      created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
e19a30
+ *      and rescan the whole {rpc_pipefs} when this happens.
e19a30
+ */
e19a30
+
e19a30
+/*
e19a30
+ * convert a presentation address string to a sockaddr_storage struct. Returns
e19a30
+ * true on success or false on failure.
e19a30
+ *
e19a30
+ * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
e19a30
+ * gssd nececessarily relies on hostname resolution and DNS AAAA records
e19a30
+ * do not generally contain scope-id's. This means that GSSAPI auth really
e19a30
+ * can't work with IPv6 link-local addresses.
e19a30
+ *
e19a30
+ * We *could* consider changing this if we did something like adopt the
e19a30
+ * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
e19a30
+ * not really feasible at present.
e19a30
+ */
e19a30
+static bool
e19a30
+gssd_addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
e19a30
+{
e19a30
+	int rc;
e19a30
+	struct addrinfo *res;
e19a30
+	struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
e19a30
+
e19a30
+#ifndef IPV6_SUPPORTED
e19a30
+	hints.ai_family = AF_INET;
e19a30
+#endif /* IPV6_SUPPORTED */
e19a30
+
e19a30
+	rc = getaddrinfo(node, port, &hints, &res;;
e19a30
+	if (rc) {
e19a30
+		printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
e19a30
+			 node, port,
e19a30
+			 rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
e19a30
+		return false;
e19a30
+	}
e19a30
+
e19a30
+#ifdef IPV6_SUPPORTED
e19a30
+	/*
e19a30
+	 * getnameinfo ignores the scopeid. If the address turns out to have
e19a30
+	 * a non-zero scopeid, we can't use it -- the resolved host might be
e19a30
+	 * completely different from the one intended.
e19a30
+	 */
e19a30
+	if (res->ai_addr->sa_family == AF_INET6) {
e19a30
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
e19a30
+		if (sin6->sin6_scope_id) {
e19a30
+			printerr(0, "ERROR: address %s has non-zero "
e19a30
+				    "sin6_scope_id!\n", node);
e19a30
+			freeaddrinfo(res);
e19a30
+			return false;
e19a30
+		}
e19a30
+	}
e19a30
+#endif /* IPV6_SUPPORTED */
e19a30
+
e19a30
+	memcpy(sa, res->ai_addr, res->ai_addrlen);
e19a30
+	freeaddrinfo(res);
e19a30
+	return true;
e19a30
+}
e19a30
+
e19a30
+/*
e19a30
+ * convert a sockaddr to a hostname
e19a30
+ */
e19a30
+static char *
e19a30
+gssd_get_servername(const char *name, const struct sockaddr *sa, const char *addr)
e19a30
+{
e19a30
+	socklen_t		addrlen;
e19a30
+	int			err;
e19a30
+	char			hbuf[NI_MAXHOST];
e19a30
+	unsigned char		buf[sizeof(struct in6_addr)];
e19a30
+
e19a30
+	while (avoid_dns) {
e19a30
+		/*
e19a30
+		 * Determine if this is a server name, or an IP address.
e19a30
+		 * If it is an IP address, do the DNS lookup otherwise
e19a30
+		 * skip the DNS lookup.
e19a30
+		 */
e19a30
+		if (strchr(name, '.') == NULL)
e19a30
+			break; /* local name */
e19a30
+		else if (inet_pton(AF_INET, name, buf) == 1)
e19a30
+			break; /* IPv4 address */
e19a30
+		else if (inet_pton(AF_INET6, name, buf) == 1)
e19a30
+			break; /* IPv6 addrss */
e19a30
+
e19a30
+		return strdup(name);
e19a30
+	}
e19a30
+
e19a30
+	switch (sa->sa_family) {
e19a30
+	case AF_INET:
e19a30
+		addrlen = sizeof(struct sockaddr_in);
e19a30
+		break;
e19a30
+#ifdef IPV6_SUPPORTED
e19a30
+	case AF_INET6:
e19a30
+		addrlen = sizeof(struct sockaddr_in6);
e19a30
+		break;
e19a30
+#endif /* IPV6_SUPPORTED */
e19a30
+	default:
e19a30
+		printerr(0, "ERROR: unrecognized addr family %d\n",
e19a30
+			 sa->sa_family);
e19a30
+		return NULL;
e19a30
+	}
e19a30
+
e19a30
+	err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
e19a30
+			  NI_NAMEREQD);
e19a30
+	if (err) {
e19a30
+		printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
e19a30
+			 addr, err == EAI_SYSTEM ? strerror(errno) :
e19a30
+						   gai_strerror(err));
e19a30
+		return NULL;
e19a30
+	}
e19a30
+
e19a30
+	return strdup(hbuf);
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_read_service_info(int dirfd, struct clnt_info *clp)
e19a30
+{
e19a30
+	int fd;
e19a30
+	FILE *info = NULL;
e19a30
+	int numfields;
e19a30
+	char *server = NULL;
e19a30
+	char *service = NULL;
e19a30
+	int program;
e19a30
+	int version;
e19a30
+	char *address = NULL;
e19a30
+	char *protoname = NULL;
e19a30
+	char *port = NULL;
e19a30
+	char *servername = NULL;
e19a30
+
e19a30
+	fd = openat(dirfd, "info", O_RDONLY);
e19a30
+	if (fd < 0) {
e19a30
+		printerr(0, "ERROR: can't open %s/info: %s\n",
e19a30
+			 clp->relpath, strerror(errno));
e19a30
+		goto fail;
e19a30
+	}
e19a30
+
e19a30
+	info = fdopen(fd, "r");
e19a30
+	if (!info) {
e19a30
+		printerr(0, "ERROR: can't fdopen %s/info: %s\n",
e19a30
+			 clp->relpath, strerror(errno));
e19a30
+		close(fd);
e19a30
+		goto fail;
e19a30
+	}
e19a30
+
e19a30
+	/*
e19a30
+	 * Some history:
e19a30
+	 *
e19a30
+	 * The first three lines were added with rpc_pipefs in 2003-01-13.
e19a30
+	 * (commit af2f003391786fb632889c02142c941b212ba4ff)
e19a30
+	 * 
e19a30
+	 * The 'protocol' line was added in 2003-06-11.
e19a30
+	 * (commit 9bd741ae48785d0c0e75cf906ff66f893d600c2d)
e19a30
+	 *
e19a30
+	 * The 'port' line was added in 2007-09-26.
e19a30
+	 * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe)
e19a30
+	 */
e19a30
+	numfields = fscanf(info,
e19a30
+			   "RPC server: %ms\n"
e19a30
+			   "service: %ms (%d) version %d\n"
e19a30
+			   "address: %ms\n"
e19a30
+			   "protocol: %ms\n"
e19a30
+			   "port: %ms\n",
e19a30
+			   &server,
e19a30
+			   &service, &program, &version,
e19a30
+			   &address,
e19a30
+			   &protoname,
e19a30
+			   &port);
e19a30
+
e19a30
+
e19a30
+	switch (numfields) {
e19a30
+	case 5:
e19a30
+		protoname = strdup("tcp");
e19a30
+		if (!protoname)
e19a30
+			goto fail;
e19a30
+		/* fall through */
e19a30
+	case 6:
e19a30
+		/* fall through */
e19a30
+	case 7:
e19a30
+		break;
e19a30
+	default:
e19a30
+		goto fail;
e19a30
+	}
e19a30
+
e19a30
+	if (!gssd_addrstr_to_sockaddr((struct sockaddr *)&clp->addr,
e19a30
+				 address, port ? port : ""))
e19a30
+		goto fail;
e19a30
+
e19a30
+	servername = gssd_get_servername(server, (struct sockaddr *)&clp->addr, address);
e19a30
+	if (!servername)
e19a30
+		goto fail;
e19a30
+
e19a30
+	if (asprintf(&clp->servicename, "%s@%s", service, servername) < 0)
e19a30
+		goto fail;
e19a30
+
e19a30
+	clp->servername = servername;
e19a30
+	clp->prog = program;
e19a30
+	clp->vers = version;
e19a30
+	clp->protocol = protoname;
e19a30
+
e19a30
+	goto out;
e19a30
+
e19a30
+fail:
e19a30
+	printerr(0, "ERROR: failed to parse %s/info\n", clp->relpath);
e19a30
+	free(servername);
e19a30
+	free(protoname);
e19a30
+	clp->servicename = NULL;
e19a30
+	clp->servername = NULL;
e19a30
+	clp->prog = 0;
e19a30
+	clp->vers = 0;
e19a30
+	clp->protocol = NULL;
e19a30
+out:
e19a30
+	if (info)
e19a30
+		fclose(info);
e19a30
+
e19a30
+	free(server);
e19a30
+	free(service);
e19a30
+	free(address);
e19a30
+	free(port);
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_destroy_client(struct clnt_info *clp)
e19a30
+{
e19a30
+	if (clp->krb5_fd >= 0) {
e19a30
+		close(clp->krb5_fd);
e19a30
+		event_del(&clp->krb5_ev);
e19a30
+	}
e19a30
+
e19a30
+	if (clp->gssd_fd >= 0) {
e19a30
+		close(clp->gssd_fd);
e19a30
+		event_del(&clp->gssd_ev);
e19a30
+	}
e19a30
+
e19a30
+	inotify_rm_watch(inotify_fd, clp->wd);
e19a30
+	free(clp->relpath);
e19a30
+	free(clp->servicename);
e19a30
+	free(clp->servername);
e19a30
+	free(clp->protocol);
e19a30
+	free(clp);
e19a30
+}
e19a30
+
e19a30
+static void gssd_scan(void);
e19a30
+
e19a30
+static void
e19a30
+gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
e19a30
+{
e19a30
+	struct clnt_info *clp = data;
e19a30
+
e19a30
+	handle_gssd_upcall(clp);
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
e19a30
+{
e19a30
+	struct clnt_info *clp = data;
e19a30
+
e19a30
+	handle_krb5_upcall(clp);
e19a30
+}
e19a30
+
e19a30
+static struct clnt_info *
e19a30
+gssd_get_clnt(struct topdir *tdi, const char *name)
e19a30
+{
e19a30
+	struct clnt_info *clp;
e19a30
+
e19a30
+	TAILQ_FOREACH(clp, &tdi->clnt_list, list)
e19a30
+		if (!strcmp(clp->name, name))
e19a30
+			return clp;
e19a30
+
e19a30
+	clp = calloc(1, sizeof(struct clnt_info));
e19a30
+	if (!clp) {
e19a30
+		printerr(0, "ERROR: can't malloc clnt_info: %s\n",
e19a30
+			 strerror(errno));
e19a30
+		return NULL;
e19a30
+	}
e19a30
+
e19a30
+	if (asprintf(&clp->relpath, "%s/%s", tdi->name, name) < 0) {
e19a30
+		clp->relpath = NULL;
e19a30
+		goto out;
e19a30
+	}
e19a30
+
e19a30
+	clp->wd = inotify_add_watch(inotify_fd, clp->relpath, IN_CREATE | IN_DELETE);
e19a30
+	if (clp->wd < 0) {
e19a30
+		if (errno != ENOENT)
e19a30
+			printerr(0, "ERROR: inotify_add_watch failed for %s: %s\n",
e19a30
+			 	clp->relpath, strerror(errno));
e19a30
+		goto out;
e19a30
+	}
e19a30
+
e19a30
+	clp->name = clp->relpath + strlen(tdi->name) + 1;
e19a30
+	clp->krb5_fd = -1;
e19a30
+	clp->gssd_fd = -1;
e19a30
+
e19a30
+	TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list);
e19a30
+	return clp;
e19a30
+
e19a30
+out:
e19a30
+	free(clp->relpath);
e19a30
+	free(clp);
e19a30
+	return NULL;
e19a30
+}
e19a30
+
e19a30
+static int
e19a30
+gssd_scan_clnt(struct clnt_info *clp)
e19a30
+{
e19a30
+	int clntfd;
e19a30
+	bool gssd_was_closed;
e19a30
+	bool krb5_was_closed;
e19a30
+
e19a30
+	gssd_was_closed = clp->gssd_fd < 0 ? true : false;
e19a30
+	krb5_was_closed = clp->krb5_fd < 0 ? true : false;
e19a30
+
e19a30
+	clntfd = openat(pipefs_fd, clp->relpath, O_RDONLY);
e19a30
+	if (clntfd < 0) {
e19a30
+		printerr(0, "ERROR: can't openat %s: %s\n",
e19a30
+			 clp->relpath, strerror(errno));
e19a30
+		return -1;
e19a30
+	}
e19a30
+
e19a30
+	if (clp->gssd_fd == -1)
e19a30
+		clp->gssd_fd = openat(clntfd, "gssd", O_RDWR | O_NONBLOCK);
e19a30
+
e19a30
+	if (clp->gssd_fd == -1 && clp->krb5_fd == -1)
e19a30
+		clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK);
e19a30
+
e19a30
+	if (gssd_was_closed && clp->gssd_fd >= 0) {
e19a30
+		event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST,
e19a30
+			  gssd_clnt_gssd_cb, clp);
e19a30
+		event_add(&clp->gssd_ev, NULL);
e19a30
+	}
e19a30
+
e19a30
+	if (krb5_was_closed && clp->krb5_fd >= 0) {
e19a30
+		event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST,
e19a30
+			  gssd_clnt_krb5_cb, clp);
e19a30
+		event_add(&clp->krb5_ev, NULL);
e19a30
+	}
e19a30
+
e19a30
+	if (clp->krb5_fd == -1 && clp->gssd_fd == -1)
e19a30
+		/* not fatal, files might appear later */
e19a30
+		goto out;
e19a30
+
e19a30
+	if (clp->prog == 0)
e19a30
+		gssd_read_service_info(clntfd, clp);
e19a30
+
e19a30
+out:
e19a30
+	close(clntfd);
e19a30
+	clp->scanned = true;
e19a30
+	return 0;
e19a30
+}
e19a30
+
e19a30
+static int
e19a30
+gssd_create_clnt(struct topdir *tdi, const char *name)
e19a30
+{
e19a30
+	struct clnt_info *clp;
e19a30
+
e19a30
+	clp = gssd_get_clnt(tdi, name);
e19a30
+	if (!clp)
e19a30
+		return -1;
e19a30
+
e19a30
+	return gssd_scan_clnt(clp);
e19a30
+}
e19a30
 
e19a30
-void
e19a30
+static struct topdir *
e19a30
+gssd_get_topdir(const char *name)
e19a30
+{
e19a30
+	struct topdir *tdi;
e19a30
+
e19a30
+	TAILQ_FOREACH(tdi, &topdir_list, list)
e19a30
+		if (!strcmp(tdi->name, name))
e19a30
+			return tdi;
e19a30
+
e19a30
+	tdi = malloc(sizeof(*tdi) + strlen(name) + 1);
e19a30
+	if (!tdi) {
e19a30
+		printerr(0, "ERROR: Couldn't allocate struct topdir\n");
e19a30
+		return NULL;
e19a30
+	}
e19a30
+
e19a30
+	tdi->wd = inotify_add_watch(inotify_fd, name, IN_CREATE);
e19a30
+	if (tdi->wd < 0) {
e19a30
+		printerr(0, "ERROR: inotify_add_watch failed for top dir %s: %s\n",
e19a30
+			 tdi->name, strerror(errno));
e19a30
+		free(tdi);
e19a30
+		return NULL;
e19a30
+	}
e19a30
+
e19a30
+	strcpy(tdi->name, name);
e19a30
+	TAILQ_INIT(&tdi->clnt_list);
e19a30
+
e19a30
+	TAILQ_INSERT_HEAD(&topdir_list, tdi, list);
e19a30
+	return tdi;
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_scan_topdir(const char *name)
e19a30
+{
e19a30
+	struct topdir *tdi;
e19a30
+	int dfd;
e19a30
+	DIR *dir;
e19a30
+	struct clnt_info *clp;
e19a30
+	struct dirent *d;
e19a30
+
e19a30
+	tdi = gssd_get_topdir(name);
e19a30
+	if (!tdi)
e19a30
+		return;
e19a30
+
e19a30
+	dfd = openat(pipefs_fd, tdi->name, O_RDONLY);
e19a30
+	if (dfd < 0) {
e19a30
+		printerr(0, "ERROR: can't openat %s: %s\n",
e19a30
+			 tdi->name, strerror(errno));
e19a30
+		return;
e19a30
+	}
e19a30
+
e19a30
+	dir = fdopendir(dfd);
e19a30
+	if (!dir) {
e19a30
+		printerr(0, "ERROR: can't fdopendir %s: %s\n",
e19a30
+			 tdi->name, strerror(errno));
e19a30
+		return;
e19a30
+	}
e19a30
+
e19a30
+	TAILQ_FOREACH(clp, &tdi->clnt_list, list)
e19a30
+		clp->scanned = false;
e19a30
+
e19a30
+	while ((d = readdir(dir))) {
e19a30
+		if (d->d_type != DT_DIR)
e19a30
+			continue;
e19a30
+
e19a30
+		if (strncmp(d->d_name, "clnt", strlen("clnt")))
e19a30
+			continue;
e19a30
+
e19a30
+		gssd_create_clnt(tdi, d->d_name);
e19a30
+	}
e19a30
+
e19a30
+	closedir(dir);
e19a30
+
e19a30
+	TAILQ_FOREACH(clp, &tdi->clnt_list, list) {
e19a30
+		void *saveprev;
e19a30
+
e19a30
+		if (clp->scanned)
e19a30
+			continue;
e19a30
+
e19a30
+		printerr(3, "destroying client %s\n", clp->relpath);
e19a30
+		saveprev = clp->list.tqe_prev;
e19a30
+		TAILQ_REMOVE(&tdi->clnt_list, clp, list);
e19a30
+		gssd_destroy_client(clp);
e19a30
+		clp = saveprev;
e19a30
+	}
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_scan(void)
e19a30
+{
e19a30
+	struct dirent *d;
e19a30
+
e19a30
+	printerr(3, "doing a full rescan\n");
e19a30
+	rewinddir(pipefs_dir);
e19a30
+
e19a30
+	while ((d = readdir(pipefs_dir))) {
e19a30
+		if (d->d_type != DT_DIR)
e19a30
+			continue;
e19a30
+
e19a30
+		if (d->d_name[0] == '.')
e19a30
+			continue;
e19a30
+
e19a30
+		gssd_scan_topdir(d->d_name);
e19a30
+	}
e19a30
+
e19a30
+	if (TAILQ_EMPTY(&topdir_list)) {
e19a30
+		printerr(0, "ERROR: the rpc_pipefs directory is empty!\n");
e19a30
+		exit(EXIT_FAILURE);
e19a30
+	}
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_scan_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
e19a30
+{
e19a30
+	gssd_scan();
e19a30
+}
e19a30
+
e19a30
+static bool
e19a30
+gssd_inotify_topdir(struct topdir *tdi, const struct inotify_event *ev)
e19a30
+{
e19a30
+	printerr(5, "inotify event for topdir (%s) - "
e19a30
+		 "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
e19a30
+		 tdi->name, ev->wd, ev->len > 0 ? ev->name : "", ev->mask);
e19a30
+
e19a30
+	if (ev->mask & IN_IGNORED) {
e19a30
+		printerr(0, "ERROR: topdir disappeared!\n");
e19a30
+		return false;
e19a30
+	}
e19a30
+
e19a30
+	if (ev->len == 0)
e19a30
+		return false;
e19a30
+
e19a30
+	if (ev->mask & IN_CREATE) {
e19a30
+		if (!(ev->mask & IN_ISDIR))
e19a30
+			return true;
e19a30
+
e19a30
+		if (strncmp(ev->name, "clnt", strlen("clnt")))
e19a30
+			return true;
e19a30
+
e19a30
+		if (gssd_create_clnt(tdi, ev->name))
e19a30
+			return false;
e19a30
+
e19a30
+		return true;
e19a30
+	} 
e19a30
+
e19a30
+	return false;
e19a30
+}
e19a30
+
e19a30
+static bool
e19a30
+gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotify_event *ev)
e19a30
+{
e19a30
+	printerr(5, "inotify event for clntdir (%s) - "
e19a30
+		 "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
e19a30
+		 clp->relpath, ev->wd, ev->len > 0 ? ev->name : "", ev->mask);
e19a30
+
e19a30
+	if (ev->mask & IN_IGNORED) {
e19a30
+		TAILQ_REMOVE(&tdi->clnt_list, clp, list);
e19a30
+		gssd_destroy_client(clp);
e19a30
+		return true;
e19a30
+	}
e19a30
+
e19a30
+	if (ev->len == 0)
e19a30
+		return false;
e19a30
+
e19a30
+	if (ev->mask & IN_CREATE) {
e19a30
+		if (!strcmp(ev->name, "gssd") ||
e19a30
+		    !strcmp(ev->name, "krb5") ||
e19a30
+		    !strcmp(ev->name, "info"))
e19a30
+			if (gssd_scan_clnt(clp))
e19a30
+				return false;
e19a30
+
e19a30
+		return true;
e19a30
+
e19a30
+	} else if (ev->mask & IN_DELETE) {
e19a30
+		if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) {
e19a30
+			close(clp->gssd_fd);
e19a30
+			event_del(&clp->gssd_ev);
e19a30
+			clp->gssd_fd = -1;
e19a30
+
e19a30
+		} else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) {
e19a30
+			close(clp->krb5_fd);
e19a30
+			event_del(&clp->krb5_ev);
e19a30
+			clp->krb5_fd = -1;
e19a30
+		}
e19a30
+
e19a30
+		return true;
e19a30
+	}
e19a30
+
e19a30
+	return false;
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
+gssd_inotify_cb(int ifd, short UNUSED(which), void *UNUSED(data))
e19a30
+{
e19a30
+	bool rescan = false;
e19a30
+	struct topdir *tdi;
e19a30
+	struct clnt_info *clp;
e19a30
+
e19a30
+	while (true) {
e19a30
+		char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
e19a30
+		const struct inotify_event *ev;
e19a30
+		ssize_t len;
e19a30
+		char *ptr;
e19a30
+
e19a30
+		len = read(ifd, buf, sizeof(buf));
e19a30
+		if (len == -1 && errno == EINTR)
e19a30
+			continue;
e19a30
+
e19a30
+		if (len <= 0)
e19a30
+			break;
e19a30
+
e19a30
+		for (ptr = buf; ptr < buf + len;
e19a30
+		     ptr += sizeof(struct inotify_event) + ev->len) {
e19a30
+			ev = (const struct inotify_event *)ptr;
e19a30
+
e19a30
+			if (ev->mask & IN_Q_OVERFLOW) {
e19a30
+				printerr(0, "ERROR: inotify queue overflow\n");
e19a30
+				rescan = true;
e19a30
+				break;
e19a30
+			}
e19a30
+
e19a30
+			TAILQ_FOREACH(tdi, &topdir_list, list) {
e19a30
+				if (tdi->wd == ev->wd) {
e19a30
+					if (!gssd_inotify_topdir(tdi, ev))
e19a30
+						rescan = true;
e19a30
+					goto found;
e19a30
+				}
e19a30
+
e19a30
+				TAILQ_FOREACH(clp, &tdi->clnt_list, list) {
e19a30
+					if (clp->wd == ev->wd) {
e19a30
+						if (!gssd_inotify_clnt(tdi, clp, ev))
e19a30
+							rescan = true;
e19a30
+						goto found;
e19a30
+					}
e19a30
+				}
e19a30
+			}
e19a30
+
e19a30
+found:
e19a30
+			if (!tdi) {
e19a30
+				printerr(5, "inotify event for unknown wd!!! - "
e19a30
+					 "ev->wd (%d) ev->name (%s) ev->mask (0x%08x)\n",
e19a30
+					 ev->wd, ev->len > 0 ? ev->name : "", ev->mask);
e19a30
+				rescan = true;
e19a30
+			}
e19a30
+		}
e19a30
+	}
e19a30
+
e19a30
+	if (rescan)
e19a30
+		gssd_scan();
e19a30
+}
e19a30
+
e19a30
+static void
e19a30
 sig_die(int signal)
e19a30
 {
e19a30
-	/* destroy krb5 machine creds */
e19a30
 	if (root_uses_machine_creds)
e19a30
 		gssd_destroy_krb5_machine_creds();
e19a30
 	printerr(1, "exiting on signal %d\n", signal);
e19a30
 	exit(0);
e19a30
 }
e19a30
 
e19a30
-void
e19a30
-sig_hup(int signal)
e19a30
-{
e19a30
-	/* don't exit on SIGHUP */
e19a30
-	printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
e19a30
-	return;
e19a30
-}
e19a30
-
e19a30
 static void
e19a30
 usage(char *progname)
e19a30
 {
e19a30
@@ -104,8 +756,9 @@ main(int argc, char *argv[])
e19a30
 	int i;
e19a30
 	extern char *optarg;
e19a30
 	char *progname;
e19a30
+	char *ccachedir = NULL;
e19a30
+	struct event sighup_ev;
e19a30
 
e19a30
-	memset(ccachesearch, 0, sizeof(ccachesearch));
e19a30
 	while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) {
e19a30
 		switch (opt) {
e19a30
 			case 'f':
e19a30
@@ -127,19 +780,13 @@ main(int argc, char *argv[])
e19a30
 				rpc_verbosity++;
e19a30
 				break;
e19a30
 			case 'p':
e19a30
-				strncpy(pipefs_dir, optarg, sizeof(pipefs_dir));
e19a30
-				if (pipefs_dir[sizeof(pipefs_dir)-1] != '\0')
e19a30
-					errx(1, "pipefs path name too long");
e19a30
+				pipefs_path = optarg;
e19a30
 				break;
e19a30
 			case 'k':
e19a30
-				strncpy(keytabfile, optarg, sizeof(keytabfile));
e19a30
-				if (keytabfile[sizeof(keytabfile)-1] != '\0')
e19a30
-					errx(1, "keytab path name too long");
e19a30
+				keytabfile = optarg;
e19a30
 				break;
e19a30
 			case 'd':
e19a30
-				strncpy(ccachedir, optarg, sizeof(ccachedir));
e19a30
-				if (ccachedir[sizeof(ccachedir)-1] != '\0')
e19a30
-					errx(1, "ccachedir path name too long");
e19a30
+				ccachedir = optarg;
e19a30
 				break;
e19a30
 			case 't':
e19a30
 				context_timeout = atoi(optarg);
e19a30
@@ -158,7 +805,7 @@ main(int argc, char *argv[])
e19a30
 #endif
e19a30
 				break;
e19a30
 			case 'D':
e19a30
-				avoid_dns = 0;
e19a30
+				avoid_dns = false;
e19a30
 				break;
e19a30
 			default:
e19a30
 				usage(argv[0]);
e19a30
@@ -174,15 +821,41 @@ main(int argc, char *argv[])
e19a30
 	 * the results of getpw*.
e19a30
 	 */
e19a30
 	if (setenv("HOME", "/", 1)) {
e19a30
-		printerr(1, "Unable to set $HOME: %s\n", strerror(errno));
e19a30
+		printerr(0, "gssd: Unable to set $HOME: %s\n", strerror(errno));
e19a30
 		exit(1);
e19a30
 	}
e19a30
 
e19a30
-	i = 0;
e19a30
-	ccachesearch[i++] = strtok(ccachedir, ":");
e19a30
-	do {
e19a30
-		ccachesearch[i++] = strtok(NULL, ":");
e19a30
-	} while (ccachesearch[i-1] != NULL && i < GSSD_MAX_CCACHE_SEARCH);
e19a30
+	if (ccachedir) {
e19a30
+		char *ccachedir_copy;
e19a30
+		char *ptr;
e19a30
+
e19a30
+		for (ptr = ccachedir, i = 2; *ptr; ptr++)
e19a30
+			if (*ptr == ':')
e19a30
+				i++;
e19a30
+
e19a30
+		ccachesearch = malloc(i * sizeof(char *));
e19a30
+	       	ccachedir_copy = strdup(ccachedir);
e19a30
+		if (!ccachedir_copy || !ccachesearch) {
e19a30
+			printerr(0, "malloc failure\n");
e19a30
+			exit(EXIT_FAILURE);
e19a30
+		}
e19a30
+
e19a30
+		i = 0;
e19a30
+		ccachesearch[i++] = strtok(ccachedir, ":");
e19a30
+		while(ccachesearch[i - 1])
e19a30
+			ccachesearch[i++] = strtok(NULL, ":");
e19a30
+
e19a30
+	} else {
e19a30
+		ccachesearch = malloc(3 * sizeof(char *));
e19a30
+		if (!ccachesearch) {
e19a30
+			printerr(0, "malloc failure\n");
e19a30
+			exit(EXIT_FAILURE);
e19a30
+		}
e19a30
+
e19a30
+		ccachesearch[0] = GSSD_DEFAULT_CRED_DIR;
e19a30
+		ccachesearch[1] = GSSD_USER_CRED_DIR;
e19a30
+		ccachesearch[2] = NULL;
e19a30
+	}
e19a30
 
e19a30
 	if (preferred_realm == NULL)
e19a30
 		gssd_k5_get_default_realm(&preferred_realm);
e19a30
@@ -197,6 +870,13 @@ main(int argc, char *argv[])
e19a30
 	if (verbosity && rpc_verbosity == 0)
e19a30
 		rpc_verbosity = verbosity;
e19a30
 	authgss_set_debug_level(rpc_verbosity);
e19a30
+#elif HAVE_LIBTIRPC_SET_DEBUG
e19a30
+	/*
e19a30
+	 * Only set the libtirpc debug level if explicitly requested via -r...
e19a30
+	 * gssd is chatty enough as it is.
e19a30
+	 */
e19a30
+	if (rpc_verbosity > 0)
e19a30
+		libtirpc_set_debug(progname, rpc_verbosity, fg);
e19a30
 #else
e19a30
         if (rpc_verbosity > 0)
e19a30
 		printerr(0, "Warning: rpcsec_gss library does not "
e19a30
@@ -206,14 +886,42 @@ main(int argc, char *argv[])
e19a30
 	if (gssd_check_mechs() != 0)
e19a30
 		errx(1, "Problem with gssapi library");
e19a30
 
e19a30
-	if (!fg)
e19a30
-		mydaemon(0, 0, pipefds);
e19a30
+	daemon_init(fg);
e19a30
+
e19a30
+	event_init();
e19a30
+
e19a30
+	pipefs_dir = opendir(pipefs_path);
e19a30
+	if (!pipefs_dir) {
e19a30
+		printerr(0, "ERROR: opendir(%s) failed: %s\n", pipefs_path, strerror(errno));
e19a30
+		exit(EXIT_FAILURE);
e19a30
+	}
e19a30
+
e19a30
+	pipefs_fd = dirfd(pipefs_dir);
e19a30
+	if (fchdir(pipefs_fd)) {
e19a30
+		printerr(0, "ERROR: fchdir(%s) failed: %s\n", pipefs_path, strerror(errno));
e19a30
+		exit(EXIT_FAILURE);
e19a30
+	}
e19a30
+
e19a30
+	inotify_fd = inotify_init1(IN_NONBLOCK);
e19a30
+	if (inotify_fd == -1) {
e19a30
+		printerr(0, "ERROR: inotify_init1 failed: %s\n", strerror(errno));
e19a30
+		exit(EXIT_FAILURE);
e19a30
+	}
e19a30
 
e19a30
 	signal(SIGINT, sig_die);
e19a30
 	signal(SIGTERM, sig_die);
e19a30
-	signal(SIGHUP, sig_hup);
e19a30
+	signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL);
e19a30
+	signal_add(&sighup_ev, NULL);
e19a30
+	event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL);
e19a30
+	event_add(&inotify_ev, NULL);
e19a30
+
e19a30
+	TAILQ_INIT(&topdir_list);
e19a30
+	gssd_scan();
e19a30
+	daemon_ready();
e19a30
 
e19a30
-	gssd_run();
e19a30
-	printerr(0, "gssd_run returned!\n");
e19a30
-	abort();
e19a30
+	event_dispatch();
e19a30
+
e19a30
+	printerr(0, "ERROR: event_dispatch() returned!\n");
e19a30
+	return EXIT_FAILURE;
e19a30
 }
e19a30
+
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/gssd.h.orig nfs-utils-1.3.0/utils/gssd/gssd.h
e19a30
--- nfs-utils-1.3.0/utils/gssd/gssd.h.orig	2016-04-15 11:42:13.917460638 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/gssd.h	2016-04-15 11:42:38.369938424 -0400
e19a30
@@ -34,14 +34,12 @@
e19a30
 #include <sys/types.h>
e19a30
 #include <sys/queue.h>
e19a30
 #include <gssapi/gssapi.h>
e19a30
+#include <event.h>
e19a30
+#include <stdbool.h>
e19a30
 
e19a30
-#define MAX_FILE_NAMELEN	32
e19a30
-#define FD_ALLOC_BLOCK		256
e19a30
 #ifndef GSSD_PIPEFS_DIR
e19a30
 #define GSSD_PIPEFS_DIR		"/var/lib/nfs/rpc_pipefs"
e19a30
 #endif
e19a30
-#define INFO			"info"
e19a30
-#define KRB5			"krb5"
e19a30
 #define DNOTIFY_SIGNAL		(SIGRTMIN + 3)
e19a30
 
e19a30
 #define GSSD_DEFAULT_CRED_DIR			"/tmp"
e19a30
@@ -50,60 +48,40 @@
e19a30
 #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX	"machine"
e19a30
 #define GSSD_DEFAULT_KEYTAB_FILE		"/etc/krb5.keytab"
e19a30
 #define GSSD_SERVICE_NAME			"nfs"
e19a30
-#define GSSD_SERVICE_NAME_LEN			3
e19a30
-#define GSSD_MAX_CCACHE_SEARCH			16
e19a30
 
e19a30
 /*
e19a30
  * The gss mechanisms that we can handle
e19a30
  */
e19a30
 enum {AUTHTYPE_KRB5, AUTHTYPE_LIPKEY};
e19a30
 
e19a30
-
e19a30
-
e19a30
-extern char			pipefs_dir[PATH_MAX];
e19a30
-extern char			keytabfile[PATH_MAX];
e19a30
-extern char			*ccachesearch[];
e19a30
+extern char		       *keytabfile;
e19a30
+extern char		      **ccachesearch;
e19a30
 extern int			use_memcache;
e19a30
 extern int			root_uses_machine_creds;
e19a30
 extern unsigned int 		context_timeout;
e19a30
 extern unsigned int rpc_timeout;
e19a30
 extern char			*preferred_realm;
e19a30
-extern int			pipefds[2];
e19a30
-
e19a30
-TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list;
e19a30
 
e19a30
 struct clnt_info {
e19a30
 	TAILQ_ENTRY(clnt_info)	list;
e19a30
-	char			*dirname;
e19a30
-	char			*pdir;
e19a30
-	int			dir_fd;
e19a30
+	int			wd;
e19a30
+	bool			scanned;
e19a30
+	char			*name;
e19a30
+	char			*relpath;
e19a30
 	char			*servicename;
e19a30
 	char			*servername;
e19a30
 	int			prog;
e19a30
 	int			vers;
e19a30
 	char			*protocol;
e19a30
 	int			krb5_fd;
e19a30
-	int			krb5_poll_index;
e19a30
-	int			krb5_close_me;
e19a30
-	int                     gssd_fd;
e19a30
-	int                     gssd_poll_index;
e19a30
-	int			gssd_close_me;
e19a30
-	struct sockaddr_storage addr;
e19a30
-};
e19a30
-
e19a30
-TAILQ_HEAD(topdirs_list_head, topdirs_info) topdirs_list;
e19a30
-
e19a30
-struct topdirs_info {
e19a30
-	TAILQ_ENTRY(topdirs_info)   list;
e19a30
-	char			*dirname;
e19a30
-	int			fd;
e19a30
+	struct event		krb5_ev;
e19a30
+	int			gssd_fd;
e19a30
+	struct event		gssd_ev;
e19a30
+	struct			sockaddr_storage addr;
e19a30
 };
e19a30
 
e19a30
-void init_client_list(void);
e19a30
-int update_client_list(void);
e19a30
 void handle_krb5_upcall(struct clnt_info *clp);
e19a30
 void handle_gssd_upcall(struct clnt_info *clp);
e19a30
-void gssd_run(void);
e19a30
 
e19a30
 
e19a30
 #endif /* _RPC_GSSD_H_ */
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig nfs-utils-1.3.0/utils/gssd/gssd_proc.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/gssd_proc.c.orig	2016-04-15 11:42:13.949461263 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/gssd_proc.c	2016-04-15 11:42:38.371938463 -0400
e19a30
@@ -9,6 +9,7 @@
e19a30
   Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
e19a30
   Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
e19a30
   Copyright (c) 2004 Kevin Coffman <kwc@umich.edu>
e19a30
+  Copyright (c) 2014 David H?rdeman <david@hardeman.nu>
e19a30
   All rights reserved, all wrongs reversed.
e19a30
 
e19a30
   Redistribution and use in source and binary forms, with or without
e19a30
@@ -52,7 +53,6 @@
e19a30
 #include <sys/socket.h>
e19a30
 #include <arpa/inet.h>
e19a30
 #include <sys/fsuid.h>
e19a30
-#include <sys/resource.h>
e19a30
 
e19a30
 #include <stdio.h>
e19a30
 #include <stdlib.h>
e19a30
@@ -79,548 +79,6 @@
e19a30
 #include "nfslib.h"
e19a30
 #include "gss_names.h"
e19a30
 
e19a30
-/*
e19a30
- * pollarray:
e19a30
- *      array of struct pollfd suitable to pass to poll. initialized to
e19a30
- *      zero - a zero struct is ignored by poll() because the events mask is 0.
e19a30
- *
e19a30
- * clnt_list:
e19a30
- *      linked list of struct clnt_info which associates a clntXXX directory
e19a30
- *	with an index into pollarray[], and other basic data about that client.
e19a30
- *
e19a30
- * Directory structure: created by the kernel
e19a30
- *      {rpc_pipefs}/{dir}/clntXX         : one per rpc_clnt struct in the kernel
e19a30
- *      {rpc_pipefs}/{dir}/clntXX/krb5    : read uid for which kernel wants
e19a30
- *					    a context, write the resulting context
e19a30
- *      {rpc_pipefs}/{dir}/clntXX/info    : stores info such as server name
e19a30
- *      {rpc_pipefs}/{dir}/clntXX/gssd    : pipe for all gss mechanisms using
e19a30
- *					    a text-based string of parameters
e19a30
- *
e19a30
- * Algorithm:
e19a30
- *      Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files.  When data is ready,
e19a30
- *      read and process; performs rpcsec_gss context initialization protocol to
e19a30
- *      get a cred for that user.  Writes result to corresponding krb5 file
e19a30
- *      in a form the kernel code will understand.
e19a30
- *      In addition, we make sure we are notified whenever anything is
e19a30
- *      created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
e19a30
- *      and rescan the whole {rpc_pipefs} when this happens.
e19a30
- */
e19a30
-
e19a30
-struct pollfd * pollarray;
e19a30
-
e19a30
-unsigned long pollsize;  /* the size of pollaray (in pollfd's) */
e19a30
-
e19a30
-/* Avoid DNS reverse lookups on server names */
e19a30
-int avoid_dns = 1;
e19a30
-
e19a30
-/*
e19a30
- * convert a presentation address string to a sockaddr_storage struct. Returns
e19a30
- * true on success or false on failure.
e19a30
- *
e19a30
- * Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
e19a30
- * gssd nececessarily relies on hostname resolution and DNS AAAA records
e19a30
- * do not generally contain scope-id's. This means that GSSAPI auth really
e19a30
- * can't work with IPv6 link-local addresses.
e19a30
- *
e19a30
- * We *could* consider changing this if we did something like adopt the
e19a30
- * Microsoft "standard" of using the ipv6-literal.net domainname, but it's
e19a30
- * not really feasible at present.
e19a30
- */
e19a30
-static int
e19a30
-addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
e19a30
-{
e19a30
-	int rc;
e19a30
-	struct addrinfo *res;
e19a30
-	struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
e19a30
-
e19a30
-#ifndef IPV6_SUPPORTED
e19a30
-	hints.ai_family = AF_INET;
e19a30
-#endif /* IPV6_SUPPORTED */
e19a30
-
e19a30
-	rc = getaddrinfo(node, port, &hints, &res;;
e19a30
-	if (rc) {
e19a30
-		printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
e19a30
-			 node, port, rc == EAI_SYSTEM ? strerror(errno) :
e19a30
-						gai_strerror(rc));
e19a30
-		return 0;
e19a30
-	}
e19a30
-
e19a30
-#ifdef IPV6_SUPPORTED
e19a30
-	/*
e19a30
-	 * getnameinfo ignores the scopeid. If the address turns out to have
e19a30
-	 * a non-zero scopeid, we can't use it -- the resolved host might be
e19a30
-	 * completely different from the one intended.
e19a30
-	 */
e19a30
-	if (res->ai_addr->sa_family == AF_INET6) {
e19a30
-		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
e19a30
-		if (sin6->sin6_scope_id) {
e19a30
-			printerr(0, "ERROR: address %s has non-zero "
e19a30
-				    "sin6_scope_id!\n", node);
e19a30
-			freeaddrinfo(res);
e19a30
-			return 0;
e19a30
-		}
e19a30
-	}
e19a30
-#endif /* IPV6_SUPPORTED */
e19a30
-
e19a30
-	memcpy(sa, res->ai_addr, res->ai_addrlen);
e19a30
-	freeaddrinfo(res);
e19a30
-	return 1;
e19a30
-}
e19a30
-
e19a30
-/*
e19a30
- * convert a sockaddr to a hostname
e19a30
- */
e19a30
-static char *
e19a30
-get_servername(const char *name, const struct sockaddr *sa, const char *addr)
e19a30
-{
e19a30
-	socklen_t		addrlen;
e19a30
-	int			err;
e19a30
-	char			*hostname;
e19a30
-	char			hbuf[NI_MAXHOST];
e19a30
-	unsigned char		buf[sizeof(struct in6_addr)];
e19a30
-
e19a30
-	if (avoid_dns) {
e19a30
-		/*
e19a30
-		 * Determine if this is a server name, or an IP address.
e19a30
-		 * If it is an IP address, do the DNS lookup otherwise
e19a30
-		 * skip the DNS lookup.
e19a30
-		 */
e19a30
-		int is_fqdn = 1;
e19a30
-		if (strchr(name, '.') == NULL)
e19a30
-			is_fqdn = 0; /* local name */
e19a30
-		else if (inet_pton(AF_INET, name, buf) == 1)
e19a30
-			is_fqdn = 0; /* IPv4 address */
e19a30
-		else if (inet_pton(AF_INET6, name, buf) == 1)
e19a30
-			is_fqdn = 0; /* IPv6 addrss */
e19a30
-
e19a30
-		if (is_fqdn) {
e19a30
-			return strdup(name);
e19a30
-		}
e19a30
-		/* Sorry, cannot avoid dns after all */
e19a30
-	}
e19a30
-
e19a30
-	switch (sa->sa_family) {
e19a30
-	case AF_INET:
e19a30
-		addrlen = sizeof(struct sockaddr_in);
e19a30
-		break;
e19a30
-#ifdef IPV6_SUPPORTED
e19a30
-	case AF_INET6:
e19a30
-		addrlen = sizeof(struct sockaddr_in6);
e19a30
-		break;
e19a30
-#endif /* IPV6_SUPPORTED */
e19a30
-	default:
e19a30
-		printerr(0, "ERROR: unrecognized addr family %d\n",
e19a30
-			 sa->sa_family);
e19a30
-		return NULL;
e19a30
-	}
e19a30
-
e19a30
-	err = getnameinfo(sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
e19a30
-			  NI_NAMEREQD);
e19a30
-	if (err) {
e19a30
-		printerr(0, "ERROR: unable to resolve %s to hostname: %s\n",
e19a30
-			 addr, err == EAI_SYSTEM ? strerror(errno) :
e19a30
-						   gai_strerror(err));
e19a30
-		return NULL;
e19a30
-	}
e19a30
-
e19a30
-	hostname = strdup(hbuf);
e19a30
-
e19a30
-	return hostname;
e19a30
-}
e19a30
-
e19a30
-/* XXX buffer problems: */
e19a30
-static int
e19a30
-read_service_info(char *info_file_name, char **servicename, char **servername,
e19a30
-		  int *prog, int *vers, char **protocol,
e19a30
-		  struct sockaddr *addr) {
e19a30
-#define INFOBUFLEN 256
e19a30
-	char		buf[INFOBUFLEN + 1];
e19a30
-	static char	server[128];
e19a30
-	int		nbytes;
e19a30
-	static char	service[128];
e19a30
-	static char	address[128];
e19a30
-	char		program[16];
e19a30
-	char		version[16];
e19a30
-	char		protoname[16];
e19a30
-	char		port[128];
e19a30
-	char		*p;
e19a30
-	int		fd = -1;
e19a30
-	int		numfields;
e19a30
-
e19a30
-	*servicename = *servername = *protocol = NULL;
e19a30
-
e19a30
-	if ((fd = open(info_file_name, O_RDONLY)) == -1) {
e19a30
-		printerr(0, "ERROR: can't open %s: %s\n", info_file_name,
e19a30
-			 strerror(errno));
e19a30
-		goto fail;
e19a30
-	}
e19a30
-	if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1)
e19a30
-		goto fail;
e19a30
-	close(fd);
e19a30
-	fd = -1;
e19a30
-	buf[nbytes] = '\0';
e19a30
-
e19a30
-	numfields = sscanf(buf,"RPC server: %127s\n"
e19a30
-		   "service: %127s %15s version %15s\n"
e19a30
-		   "address: %127s\n"
e19a30
-		   "protocol: %15s\n",
e19a30
-		   server,
e19a30
-		   service, program, version,
e19a30
-		   address,
e19a30
-		   protoname);
e19a30
-
e19a30
-	if (numfields == 5) {
e19a30
-		strcpy(protoname, "tcp");
e19a30
-	} else if (numfields != 6) {
e19a30
-		goto fail;
e19a30
-	}
e19a30
-
e19a30
-	port[0] = '\0';
e19a30
-	if ((p = strstr(buf, "port")) != NULL)
e19a30
-		sscanf(p, "port: %127s\n", port);
e19a30
-
e19a30
-	/* get program, and version numbers */
e19a30
-	*prog = atoi(program + 1); /* skip open paren */
e19a30
-	*vers = atoi(version);
e19a30
-
e19a30
-	if (!addrstr_to_sockaddr(addr, address, port))
e19a30
-		goto fail;
e19a30
-
e19a30
-	*servername = get_servername(server, addr, address);
e19a30
-	if (*servername == NULL)
e19a30
-		goto fail;
e19a30
-
e19a30
-	nbytes = snprintf(buf, INFOBUFLEN, "%s@%s", service, *servername);
e19a30
-	if (nbytes > INFOBUFLEN)
e19a30
-		goto fail;
e19a30
-
e19a30
-	if (!(*servicename = calloc(strlen(buf) + 1, 1)))
e19a30
-		goto fail;
e19a30
-	memcpy(*servicename, buf, strlen(buf));
e19a30
-
e19a30
-	if (!(*protocol = strdup(protoname)))
e19a30
-		goto fail;
e19a30
-	return 0;
e19a30
-fail:
e19a30
-	printerr(0, "ERROR: failed to read service info\n");
e19a30
-	if (fd != -1) close(fd);
e19a30
-	free(*servername);
e19a30
-	free(*servicename);
e19a30
-	free(*protocol);
e19a30
-	*servicename = *servername = *protocol = NULL;
e19a30
-	return -1;
e19a30
-}
e19a30
-
e19a30
-static void
e19a30
-destroy_client(struct clnt_info *clp)
e19a30
-{
e19a30
-	if (clp->krb5_poll_index != -1)
e19a30
-		memset(&pollarray[clp->krb5_poll_index], 0,
e19a30
-					sizeof(struct pollfd));
e19a30
-	if (clp->gssd_poll_index != -1)
e19a30
-		memset(&pollarray[clp->gssd_poll_index], 0,
e19a30
-					sizeof(struct pollfd));
e19a30
-	if (clp->dir_fd != -1) close(clp->dir_fd);
e19a30
-	if (clp->krb5_fd != -1) close(clp->krb5_fd);
e19a30
-	if (clp->gssd_fd != -1) close(clp->gssd_fd);
e19a30
-	free(clp->dirname);
e19a30
-	free(clp->pdir);
e19a30
-	free(clp->servicename);
e19a30
-	free(clp->servername);
e19a30
-	free(clp->protocol);
e19a30
-	free(clp);
e19a30
-}
e19a30
-
e19a30
-static struct clnt_info *
e19a30
-insert_new_clnt(void)
e19a30
-{
e19a30
-	struct clnt_info	*clp = NULL;
e19a30
-
e19a30
-	if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) {
e19a30
-		printerr(0, "ERROR: can't malloc clnt_info: %s\n",
e19a30
-			 strerror(errno));
e19a30
-		goto out;
e19a30
-	}
e19a30
-	clp->krb5_poll_index = -1;
e19a30
-	clp->gssd_poll_index = -1;
e19a30
-	clp->krb5_fd = -1;
e19a30
-	clp->gssd_fd = -1;
e19a30
-	clp->dir_fd = -1;
e19a30
-
e19a30
-	TAILQ_INSERT_HEAD(&clnt_list, clp, list);
e19a30
-out:
e19a30
-	return clp;
e19a30
-}
e19a30
-
e19a30
-static int
e19a30
-process_clnt_dir_files(struct clnt_info * clp)
e19a30
-{
e19a30
-	char	name[PATH_MAX];
e19a30
-	char	gname[PATH_MAX];
e19a30
-	char	info_file_name[PATH_MAX];
e19a30
-
e19a30
-	if (clp->gssd_close_me) {
e19a30
-		printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
e19a30
-		close(clp->gssd_fd);
e19a30
-		memset(&pollarray[clp->gssd_poll_index], 0,
e19a30
-			sizeof(struct pollfd));
e19a30
-		clp->gssd_fd = -1;
e19a30
-		clp->gssd_poll_index = -1;
e19a30
-		clp->gssd_close_me = 0;
e19a30
-	}
e19a30
-	if (clp->krb5_close_me) {
e19a30
-		printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
e19a30
-		close(clp->krb5_fd);
e19a30
-		memset(&pollarray[clp->krb5_poll_index], 0,
e19a30
-			sizeof(struct pollfd));
e19a30
-		clp->krb5_fd = -1;
e19a30
-		clp->krb5_poll_index = -1;
e19a30
-		clp->krb5_close_me = 0;
e19a30
-	}
e19a30
-
e19a30
-	if (clp->gssd_fd == -1) {
e19a30
-		snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
e19a30
-		clp->gssd_fd = open(gname, O_RDWR);
e19a30
-	}
e19a30
-	if (clp->gssd_fd == -1) {
e19a30
-		if (clp->krb5_fd == -1) {
e19a30
-			snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
e19a30
-			clp->krb5_fd = open(name, O_RDWR);
e19a30
-		}
e19a30
-
e19a30
-		/* If we opened a gss-specific pipe, let's try opening
e19a30
-		 * the new upcall pipe again. If we succeed, close
e19a30
-		 * gss-specific pipe(s).
e19a30
-		 */
e19a30
-		if (clp->krb5_fd != -1) {
e19a30
-			clp->gssd_fd = open(gname, O_RDWR);
e19a30
-			if (clp->gssd_fd != -1) {
e19a30
-				if (clp->krb5_fd != -1)
e19a30
-					close(clp->krb5_fd);
e19a30
-				clp->krb5_fd = -1;
e19a30
-			}
e19a30
-		}
e19a30
-	}
e19a30
-
e19a30
-	if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
e19a30
-		return -1;
e19a30
-	snprintf(info_file_name, sizeof(info_file_name), "%s/info",
e19a30
-			clp->dirname);
e19a30
-	if (clp->prog == 0)
e19a30
-		read_service_info(info_file_name, &clp->servicename,
e19a30
-				  &clp->servername, &clp->prog, &clp->vers,
e19a30
-				  &clp->protocol, (struct sockaddr *) &clp->addr);
e19a30
-	return 0;
e19a30
-}
e19a30
-
e19a30
-static int
e19a30
-get_poll_index(int *ind)
e19a30
-{
e19a30
-	unsigned int i;
e19a30
-
e19a30
-	*ind = -1;
e19a30
-	for (i=0; i
e19a30
-		if (pollarray[i].events == 0) {
e19a30
-			*ind = i;
e19a30
-			break;
e19a30
-		}
e19a30
-	}
e19a30
-	if (*ind == -1) {
e19a30
-		printerr(0, "ERROR: No pollarray slots open\n");
e19a30
-		return -1;
e19a30
-	}
e19a30
-	return 0;
e19a30
-}
e19a30
-
e19a30
-
e19a30
-static int
e19a30
-insert_clnt_poll(struct clnt_info *clp)
e19a30
-{
e19a30
-	if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
e19a30
-		if (get_poll_index(&clp->gssd_poll_index)) {
e19a30
-			printerr(0, "ERROR: Too many gssd clients\n");
e19a30
-			return -1;
e19a30
-		}
e19a30
-		pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
e19a30
-		pollarray[clp->gssd_poll_index].events |= POLLIN;
e19a30
-	}
e19a30
-
e19a30
-	if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
e19a30
-		if (get_poll_index(&clp->krb5_poll_index)) {
e19a30
-			printerr(0, "ERROR: Too many krb5 clients\n");
e19a30
-			return -1;
e19a30
-		}
e19a30
-		pollarray[clp->krb5_poll_index].fd = clp->krb5_fd;
e19a30
-		pollarray[clp->krb5_poll_index].events |= POLLIN;
e19a30
-	}
e19a30
-
e19a30
-	return 0;
e19a30
-}
e19a30
-
e19a30
-static void
e19a30
-process_clnt_dir(char *dir, char *pdir)
e19a30
-{
e19a30
-	struct clnt_info *	clp;
e19a30
-
e19a30
-	if (!(clp = insert_new_clnt()))
e19a30
-		goto fail_destroy_client;
e19a30
-
e19a30
-	if (!(clp->pdir = strdup(pdir)))
e19a30
-		goto fail_destroy_client;
e19a30
-
e19a30
-	/* An extra for the '/', and an extra for the null */
e19a30
-	if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
e19a30
-		goto fail_destroy_client;
e19a30
-	}
e19a30
-	sprintf(clp->dirname, "%s/%s", pdir, dir);
e19a30
-	if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
e19a30
-		if (errno != ENOENT)
e19a30
-			printerr(0, "ERROR: can't open %s: %s\n",
e19a30
-				 clp->dirname, strerror(errno));
e19a30
-		goto fail_destroy_client;
e19a30
-	}
e19a30
-	fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL);
e19a30
-	fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT);
e19a30
-
e19a30
-	if (process_clnt_dir_files(clp))
e19a30
-		goto fail_keep_client;
e19a30
-
e19a30
-	if (insert_clnt_poll(clp))
e19a30
-		goto fail_destroy_client;
e19a30
-
e19a30
-	return;
e19a30
-
e19a30
-fail_destroy_client:
e19a30
-	if (clp) {
e19a30
-		TAILQ_REMOVE(&clnt_list, clp, list);
e19a30
-		destroy_client(clp);
e19a30
-	}
e19a30
-fail_keep_client:
e19a30
-	/* We couldn't find some subdirectories, but we keep the client
e19a30
-	 * around in case we get a notification on the directory when the
e19a30
-	 * subdirectories are created. */
e19a30
-	return;
e19a30
-}
e19a30
-
e19a30
-void
e19a30
-init_client_list(void)
e19a30
-{
e19a30
-	struct rlimit rlim;
e19a30
-	TAILQ_INIT(&clnt_list);
e19a30
-	/* Eventually plan to grow/shrink poll array: */
e19a30
-	pollsize = FD_ALLOC_BLOCK;
e19a30
-	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0 &&
e19a30
-	    rlim.rlim_cur != RLIM_INFINITY)
e19a30
-		pollsize = rlim.rlim_cur;
e19a30
-	pollarray = calloc(pollsize, sizeof(struct pollfd));
e19a30
-}
e19a30
-
e19a30
-/*
e19a30
- * This is run after a DNOTIFY signal, and should clear up any
e19a30
- * directories that are no longer around, and re-scan any existing
e19a30
- * directories, since the DNOTIFY could have been in there.
e19a30
- */
e19a30
-static void
e19a30
-update_old_clients(struct dirent **namelist, int size, char *pdir)
e19a30
-{
e19a30
-	struct clnt_info *clp;
e19a30
-	void *saveprev;
e19a30
-	int i, stillhere;
e19a30
-	char fname[PATH_MAX];
e19a30
-
e19a30
-	for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
e19a30
-		/* only compare entries in the global list that are from the
e19a30
-		 * same pipefs parent directory as "pdir"
e19a30
-		 */
e19a30
-		if (strcmp(clp->pdir, pdir) != 0) continue;
e19a30
-
e19a30
-		stillhere = 0;
e19a30
-		for (i=0; i < size; i++) {
e19a30
-			snprintf(fname, sizeof(fname), "%s/%s",
e19a30
-				 pdir, namelist[i]->d_name);
e19a30
-			if (strcmp(clp->dirname, fname) == 0) {
e19a30
-				stillhere = 1;
e19a30
-				break;
e19a30
-			}
e19a30
-		}
e19a30
-		if (!stillhere) {
e19a30
-			printerr(2, "destroying client %s\n", clp->dirname);
e19a30
-			saveprev = clp->list.tqe_prev;
e19a30
-			TAILQ_REMOVE(&clnt_list, clp, list);
e19a30
-			destroy_client(clp);
e19a30
-			clp = saveprev;
e19a30
-		}
e19a30
-	}
e19a30
-	for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
e19a30
-		if (!process_clnt_dir_files(clp))
e19a30
-			insert_clnt_poll(clp);
e19a30
-	}
e19a30
-}
e19a30
-
e19a30
-/* Search for a client by directory name, return 1 if found, 0 otherwise */
e19a30
-static int
e19a30
-find_client(char *dirname, char *pdir)
e19a30
-{
e19a30
-	struct clnt_info	*clp;
e19a30
-	char fname[PATH_MAX];
e19a30
-
e19a30
-	for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
e19a30
-		snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
e19a30
-		if (strcmp(clp->dirname, fname) == 0)
e19a30
-			return 1;
e19a30
-	}
e19a30
-	return 0;
e19a30
-}
e19a30
-
e19a30
-static int
e19a30
-process_pipedir(char *pipe_name)
e19a30
-{
e19a30
-	struct dirent **namelist;
e19a30
-	int i, j;
e19a30
-
e19a30
-	if (chdir(pipe_name) < 0) {
e19a30
-		printerr(0, "ERROR: can't chdir to %s: %s\n",
e19a30
-			 pipe_name, strerror(errno));
e19a30
-		return -1;
e19a30
-	}
e19a30
-
e19a30
-	j = scandir(pipe_name, &namelist, NULL, alphasort);
e19a30
-	if (j < 0) {
e19a30
-		printerr(0, "ERROR: can't scandir %s: %s\n",
e19a30
-			 pipe_name, strerror(errno));
e19a30
-		return -1;
e19a30
-	}
e19a30
-
e19a30
-	update_old_clients(namelist, j, pipe_name);
e19a30
-	for (i=0; i < j; i++) {
e19a30
-		if (!strncmp(namelist[i]->d_name, "clnt", 4)
e19a30
-		    && !find_client(namelist[i]->d_name, pipe_name))
e19a30
-			process_clnt_dir(namelist[i]->d_name, pipe_name);
e19a30
-		free(namelist[i]);
e19a30
-	}
e19a30
-
e19a30
-	free(namelist);
e19a30
-
e19a30
-	return 0;
e19a30
-}
e19a30
-
e19a30
-/* Used to read (and re-read) list of clients, set up poll array. */
e19a30
-int
e19a30
-update_client_list(void)
e19a30
-{
e19a30
-	int retval = -1;
e19a30
-	struct topdirs_info *tdi;
e19a30
-
e19a30
-	TAILQ_FOREACH(tdi, &topdirs_list, list) {
e19a30
-		retval = process_pipedir(tdi->dirname);
e19a30
-		if (retval)
e19a30
-			printerr(1, "WARNING: error processing %s\n",
e19a30
-				 tdi->dirname);
e19a30
-
e19a30
-	}
e19a30
-	return retval;
e19a30
-}
e19a30
-
e19a30
 /* Encryption types supported by the kernel rpcsec_gss code */
e19a30
 int num_krb5_enctypes = 0;
e19a30
 krb5_enctype *krb5_enctypes = NULL;
e19a30
@@ -691,7 +149,7 @@ do_downcall(int k5_fd, uid_t uid, struct
e19a30
 	unsigned int timeout = context_timeout;
e19a30
 	unsigned int buf_size = 0;
e19a30
 
e19a30
-	printerr(1, "doing downcall: lifetime_rec=%u acceptor=%.*s\n",
e19a30
+	printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n",
e19a30
 		lifetime_rec, acceptor->length, acceptor->value);
e19a30
 	buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
e19a30
 		sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
e19a30
@@ -730,7 +188,7 @@ do_error_downcall(int k5_fd, uid_t uid,
e19a30
 	unsigned int timeout = 0;
e19a30
 	int	zero = 0;
e19a30
 
e19a30
-	printerr(1, "doing error downcall\n");
e19a30
+	printerr(2, "doing error downcall\n");
e19a30
 
e19a30
 	if (WRITE_BYTES(&p, end, uid)) goto out_err;
e19a30
 	if (WRITE_BYTES(&p, end, timeout)) goto out_err;
e19a30
@@ -772,7 +230,7 @@ populate_port(struct sockaddr *sa, const
e19a30
 	switch (sa->sa_family) {
e19a30
 	case AF_INET:
e19a30
 		if (s4->sin_port != 0) {
e19a30
-			printerr(2, "DEBUG: port already set to %d\n",
e19a30
+			printerr(4, "DEBUG: port already set to %d\n",
e19a30
 				 ntohs(s4->sin_port));
e19a30
 			return 1;
e19a30
 		}
e19a30
@@ -780,7 +238,7 @@ populate_port(struct sockaddr *sa, const
e19a30
 #ifdef IPV6_SUPPORTED
e19a30
 	case AF_INET6:
e19a30
 		if (s6->sin6_port != 0) {
e19a30
-			printerr(2, "DEBUG: port already set to %d\n",
e19a30
+			printerr(4, "DEBUG: port already set to %d\n",
e19a30
 				 ntohs(s6->sin6_port));
e19a30
 			return 1;
e19a30
 		}
e19a30
@@ -941,7 +399,7 @@ create_auth_rpc_client(struct clnt_info
e19a30
 	auth = authgss_create_default(rpc_clnt, tgtname, &sec);
e19a30
 	if (!auth) {
e19a30
 		/* Our caller should print appropriate message */
e19a30
-		printerr(2, "WARNING: Failed to create krb5 context for "
e19a30
+		printerr(1, "WARNING: Failed to create krb5 context for "
e19a30
 			    "user with uid %d for server %s\n",
e19a30
 			 uid, tgtname);
e19a30
 		goto out_fail;
e19a30
@@ -1032,7 +490,7 @@ krb5_not_machine_creds(struct clnt_info
e19a30
 	char		**dname;
e19a30
 	int		err, resp = -1;
e19a30
 
e19a30
-	printerr(1, "krb5_not_machine_creds: uid %d tgtname %s\n", 
e19a30
+	printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", 
e19a30
 		uid, tgtname);
e19a30
 
e19a30
 	*chg_err = change_identity(uid);
e19a30
@@ -1079,7 +537,7 @@ krb5_use_machine_creds(struct clnt_info
e19a30
 	int	nocache = 0;
e19a30
 	int	success = 0;
e19a30
 
e19a30
-	printerr(1, "krb5_use_machine_creds: uid %d tgtname %s\n", 
e19a30
+	printerr(2, "krb5_use_machine_creds: uid %d tgtname %s\n", 
e19a30
 		uid, tgtname);
e19a30
 
e19a30
 	do {
e19a30
@@ -1149,8 +607,6 @@ process_krb5_upcall(struct clnt_info *cl
e19a30
 	gss_OID			mech;
e19a30
 	gss_buffer_desc		acceptor  = {0};
e19a30
 
e19a30
-	printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
e19a30
-
e19a30
 	token.length = 0;
e19a30
 	token.value = NULL;
e19a30
 	memset(&pd, 0, sizeof(struct authgss_private_data));
e19a30
@@ -1176,8 +632,6 @@ process_krb5_upcall(struct clnt_info *cl
e19a30
 	 * used for this case is not important.
e19a30
 	 *
e19a30
 	 */
e19a30
-	printerr(2, "%s: service is '%s'\n", __func__,
e19a30
-		 service ? service : "<null>");
e19a30
 	if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
e19a30
 				service == NULL)) {
e19a30
 
e19a30
@@ -1191,7 +645,7 @@ process_krb5_upcall(struct clnt_info *cl
e19a30
 			/* Child: fall through to rest of function */
e19a30
 			childpid = getpid();
e19a30
 			unsetenv("KRB5CCNAME");
e19a30
-			printerr(1, "CHILD forked pid %d \n", childpid);
e19a30
+			printerr(2, "CHILD forked pid %d \n", childpid);
e19a30
 			break;
e19a30
 		case -1:
e19a30
 			/* fork() failed! */
e19a30
@@ -1224,9 +678,7 @@ no_fork:
e19a30
 			if (auth == NULL)
e19a30
 				goto out_return_error;
e19a30
 		} else {
e19a30
-			printerr(1, "WARNING: Failed to create krb5 context "
e19a30
-				 "for user with uid %d for server %s\n",
e19a30
-				 uid, clp->servername);
e19a30
+			/* krb5_not_machine_creds logs the error */
e19a30
 			goto out_return_error;
e19a30
 		}
e19a30
 	}
e19a30
@@ -1257,7 +709,7 @@ no_fork:
e19a30
 	 * try to use it after this point.
e19a30
 	 */
e19a30
 	if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
e19a30
-		printerr(0, "WARNING: Failed to serialize krb5 context for "
e19a30
+		printerr(1, "WARNING: Failed to serialize krb5 context for "
e19a30
 			    "user with uid %d for server %s\n",
e19a30
 			 uid, clp->servername);
e19a30
 		goto out_return_error;
e19a30
@@ -1300,6 +752,8 @@ handle_krb5_upcall(struct clnt_info *clp
e19a30
 		return;
e19a30
 	}
e19a30
 
e19a30
+	printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath);
e19a30
+
e19a30
 	process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
e19a30
 }
e19a30
 
e19a30
@@ -1311,85 +765,66 @@ handle_gssd_upcall(struct clnt_info *clp
e19a30
 	int			lbuflen = 0;
e19a30
 	char			*p;
e19a30
 	char			*mech = NULL;
e19a30
+	char			*uidstr = NULL;
e19a30
 	char			*target = NULL;
e19a30
 	char			*service = NULL;
e19a30
 	char			*enctypes = NULL;
e19a30
 
e19a30
-	printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
e19a30
-
e19a30
 	if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
e19a30
 		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
 			    "failed reading request\n");
e19a30
 		return;
e19a30
 	}
e19a30
-	printerr(2, "%s: '%s'\n", __func__, lbuf);
e19a30
 
e19a30
-	/* find the mechanism name */
e19a30
-	if ((p = strstr(lbuf, "mech=")) != NULL) {
e19a30
-		mech = malloc(lbuflen);
e19a30
-		if (!mech)
e19a30
-			goto out;
e19a30
-		if (sscanf(p, "mech=%s", mech) != 1) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				    "failed to parse gss mechanism name "
e19a30
-				    "in upcall string '%s'\n", lbuf);
e19a30
-			goto out;
e19a30
-		}
e19a30
-	} else {
e19a30
+	printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath);
e19a30
+
e19a30
+	for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) {
e19a30
+		if (!strncmp(p, "mech=", strlen("mech=")))
e19a30
+			mech = p + strlen("mech=");
e19a30
+		else if (!strncmp(p, "uid=", strlen("uid=")))
e19a30
+			uidstr = p + strlen("uid=");
e19a30
+		else if (!strncmp(p, "enctypes=", strlen("enctypes=")))
e19a30
+			enctypes = p + strlen("enctypes=");
e19a30
+		else if (!strncmp(p, "target=", strlen("target=")))
e19a30
+			target = p + strlen("target=");
e19a30
+		else if (!strncmp(p, "service=", strlen("service=")))
e19a30
+			service = p + strlen("service=");
e19a30
+	}
e19a30
+
e19a30
+	if (!mech || strlen(mech) < 1) {
e19a30
 		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
 			    "failed to find gss mechanism name "
e19a30
 			    "in upcall string '%s'\n", lbuf);
e19a30
-		goto out;
e19a30
+		return;
e19a30
 	}
e19a30
 
e19a30
-	/* read uid */
e19a30
-	if ((p = strstr(lbuf, "uid=")) != NULL) {
e19a30
-		if (sscanf(p, "uid=%d", &uid) != 1) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				    "failed to parse uid "
e19a30
-				    "in upcall string '%s'\n", lbuf);
e19a30
-			goto out;
e19a30
-		}
e19a30
-	} else {
e19a30
+	if (uidstr) {
e19a30
+		uid = (uid_t)strtol(uidstr, &p, 10);
e19a30
+		if (p == uidstr || *p != '\0')
e19a30
+			uidstr = NULL;
e19a30
+	}
e19a30
+
e19a30
+	if (!uidstr) {
e19a30
 		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
 			    "failed to find uid "
e19a30
 			    "in upcall string '%s'\n", lbuf);
e19a30
-		goto out;
e19a30
+		return;
e19a30
 	}
e19a30
 
e19a30
-	/* read supported encryption types if supplied */
e19a30
-	if ((p = strstr(lbuf, "enctypes=")) != NULL) {
e19a30
-		enctypes = malloc(lbuflen);
e19a30
-		if (!enctypes)
e19a30
-			goto out;
e19a30
-		if (sscanf(p, "enctypes=%s", enctypes) != 1) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				    "failed to parse encryption types "
e19a30
-				    "in upcall string '%s'\n", lbuf);
e19a30
-			goto out;
e19a30
-		}
e19a30
-		if (parse_enctypes(enctypes) != 0) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				"parsing encryption types failed: errno %d\n", errno);
e19a30
-		}
e19a30
+	if (enctypes && parse_enctypes(enctypes) != 0) {
e19a30
+		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
+			 "parsing encryption types failed: errno %d\n", errno);
e19a30
+		return;
e19a30
 	}
e19a30
 
e19a30
-	/* read target name */
e19a30
-	if ((p = strstr(lbuf, "target=")) != NULL) {
e19a30
-		target = malloc(lbuflen);
e19a30
-		if (!target)
e19a30
-			goto out;
e19a30
-		if (sscanf(p, "target=%s", target) != 1) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				    "failed to parse target name "
e19a30
-				    "in upcall string '%s'\n", lbuf);
e19a30
-			goto out;
e19a30
-		}
e19a30
+	if (target && strlen(target) < 1) {
e19a30
+		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
+			 "failed to parse target name "
e19a30
+			 "in upcall string '%s'\n", lbuf);
e19a30
+		return;
e19a30
 	}
e19a30
 
e19a30
 	/*
e19a30
-	 * read the service name
e19a30
-	 *
e19a30
 	 * The presence of attribute "service=" indicates that machine
e19a30
 	 * credentials should be used for this request.  If the value
e19a30
 	 * is "*", then any machine credentials available can be used.
e19a30
@@ -1397,16 +832,11 @@ handle_gssd_upcall(struct clnt_info *clp
e19a30
 	 * the specified service name (always "nfs" for now) should be
e19a30
 	 * used.
e19a30
 	 */
e19a30
-	if ((p = strstr(lbuf, "service=")) != NULL) {
e19a30
-		service = malloc(lbuflen);
e19a30
-		if (!service)
e19a30
-			goto out;
e19a30
-		if (sscanf(p, "service=%s", service) != 1) {
e19a30
-			printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
-				    "failed to parse service type "
e19a30
-				    "in upcall string '%s'\n", lbuf);
e19a30
-			goto out;
e19a30
-		}
e19a30
+	if (service && strlen(service) < 1) {
e19a30
+		printerr(0, "WARNING: handle_gssd_upcall: "
e19a30
+			 "failed to parse service type "
e19a30
+			 "in upcall string '%s'\n", lbuf);
e19a30
+		return;
e19a30
 	}
e19a30
 
e19a30
 	if (strcmp(mech, "krb5") == 0 && clp->servername)
e19a30
@@ -1417,13 +847,5 @@ handle_gssd_upcall(struct clnt_info *clp
e19a30
 				 "received unknown gss mech '%s'\n", mech);
e19a30
 		do_error_downcall(clp->gssd_fd, uid, -EACCES);
e19a30
 	}
e19a30
-
e19a30
-out:
e19a30
-	free(lbuf);
e19a30
-	free(mech);
e19a30
-	free(enctypes);
e19a30
-	free(target);
e19a30
-	free(service);
e19a30
-	return;
e19a30
 }
e19a30
 
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/gss_util.h.orig nfs-utils-1.3.0/utils/gssd/gss_util.h
e19a30
--- nfs-utils-1.3.0/utils/gssd/gss_util.h.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/gss_util.h	2016-04-15 11:42:38.368938404 -0400
e19a30
@@ -52,6 +52,4 @@ int gssd_check_mechs(void);
e19a30
 		gss_krb5_set_allowable_enctypes(min, cred, num, types)
e19a30
 #endif
e19a30
 
e19a30
-extern int avoid_dns;
e19a30
-
e19a30
 #endif /* _GSS_UTIL_H_ */
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig nfs-utils-1.3.0/utils/gssd/krb5_util.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/krb5_util.c.orig	2016-04-15 11:42:13.953461341 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/krb5_util.c	2016-04-15 11:42:38.372938482 -0400
e19a30
@@ -356,7 +356,7 @@ gssd_get_single_krb5_cred(krb5_context c
e19a30
 	 */
e19a30
 	now += 300;
e19a30
 	if (ple->ccname && ple->endtime > now && !nocache) {
e19a30
-		printerr(2, "INFO: Credentials in CC '%s' are good until %d\n",
e19a30
+		printerr(3, "INFO: Credentials in CC '%s' are good until %d\n",
e19a30
 			 ple->ccname, ple->endtime);
e19a30
 		code = 0;
e19a30
 		goto out;
e19a30
@@ -383,7 +383,7 @@ gssd_get_single_krb5_cred(krb5_context c
e19a30
 			 "tickets.  May have problems behind a NAT.\n");
e19a30
 #ifdef TEST_SHORT_LIFETIME
e19a30
 	/* set a short lifetime (for debugging only!) */
e19a30
-	printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
e19a30
+	printerr(1, "WARNING: Using (debug) short machine cred lifetime!\n");
e19a30
 	krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60);
e19a30
 #endif
e19a30
 	opts = init_opts;
e19a30
@@ -451,8 +451,7 @@ gssd_get_single_krb5_cred(krb5_context c
e19a30
 	}
e19a30
 
e19a30
 	code = 0;
e19a30
-	printerr(2, "Successfully obtained machine credentials for "
e19a30
-		 "principal '%s' stored in ccache '%s'\n", pname, cc_name);
e19a30
+	printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name);
e19a30
   out:
e19a30
 #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
e19a30
 	if (init_opts)
e19a30
@@ -477,7 +476,7 @@ gssd_set_krb5_ccache_name(char *ccname)
e19a30
 #ifdef USE_GSS_KRB5_CCACHE_NAME
e19a30
 	u_int	maj_stat, min_stat;
e19a30
 
e19a30
-	printerr(2, "using gss_krb5_ccache_name to select krb5 ccache %s\n",
e19a30
+	printerr(3, "using gss_krb5_ccache_name to select krb5 ccache %s\n",
e19a30
 		 ccname);
e19a30
 	maj_stat = gss_krb5_ccache_name(&min_stat, ccname, NULL);
e19a30
 	if (maj_stat != GSS_S_COMPLETE) {
e19a30
@@ -492,7 +491,7 @@ gssd_set_krb5_ccache_name(char *ccname)
e19a30
 	 * function above for which there is no generic gssapi
e19a30
 	 * equivalent.)
e19a30
 	 */
e19a30
-	printerr(2, "using environment variable to select krb5 ccache %s\n",
e19a30
+	printerr(3, "using environment variable to select krb5 ccache %s\n",
e19a30
 		 ccname);
e19a30
 	setenv("KRB5CCNAME", ccname, 1);
e19a30
 #endif
e19a30
@@ -1093,8 +1092,8 @@ gssd_setup_krb5_user_gss_ccache(uid_t ui
e19a30
 	struct dirent		*d;
e19a30
 	int			err, i, j;
e19a30
 
e19a30
-	printerr(2, "getting credentials for client with uid %u for "
e19a30
-		    "server %s\n", uid, servername);
e19a30
+	printerr(3, "looking for client creds with uid %u for "
e19a30
+		    "server %s in %s\n", uid, servername, dirpattern);
e19a30
 
e19a30
 	for (i = 0, j = 0; dirpattern[i] != '\0'; i++) {
e19a30
 		switch (dirpattern[i]) {
e19a30
@@ -1410,16 +1409,21 @@ gssd_acquire_krb5_cred(gss_cred_id_t *gs
e19a30
 int
e19a30
 gssd_acquire_user_cred(gss_cred_id_t *gss_cred)
e19a30
 {
e19a30
-	OM_uint32 min_stat;
e19a30
+	OM_uint32 maj_stat, min_stat;
e19a30
 	int ret;
e19a30
 
e19a30
 	ret = gssd_acquire_krb5_cred(gss_cred);
e19a30
 
e19a30
 	/* force validation of cred to check for expiry */
e19a30
 	if (ret == 0) {
e19a30
-		if (gss_inquire_cred(&min_stat, *gss_cred, NULL, NULL,
e19a30
-				     NULL, NULL) != GSS_S_COMPLETE)
e19a30
-			ret = -1;
e19a30
+		maj_stat = gss_inquire_cred(&min_stat, *gss_cred, 
e19a30
+			NULL, NULL, NULL, NULL);
e19a30
+		if (maj_stat != GSS_S_COMPLETE) {
e19a30
+			if (get_verbosity() > 0)
e19a30
+				pgsserr("gss_inquire_cred",
e19a30
+					maj_stat, min_stat, &krb5oid);
e19a30
+				ret = -1;
e19a30
+			}
e19a30
 	}
e19a30
 
e19a30
 	return ret;
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/Makefile.am.orig nfs-utils-1.3.0/utils/gssd/Makefile.am
e19a30
--- nfs-utils-1.3.0/utils/gssd/Makefile.am.orig	2016-04-15 11:42:13.942461126 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/Makefile.am	2016-04-15 11:42:38.367938385 -0400
e19a30
@@ -29,7 +29,6 @@ COMMON_SRCS = \
e19a30
 gssd_SOURCES = \
e19a30
 	$(COMMON_SRCS) \
e19a30
 	gssd.c \
e19a30
-	gssd_main_loop.c \
e19a30
 	gssd_proc.c \
e19a30
 	krb5_util.c \
e19a30
 	\
e19a30
@@ -37,12 +36,23 @@ gssd_SOURCES = \
e19a30
 	krb5_util.h \
e19a30
 	write_bytes.h
e19a30
 
e19a30
-gssd_LDADD =	../../support/nfs/libnfs.a \
e19a30
-		$(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS)
e19a30
-gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC)
e19a30
+gssd_LDADD = \
e19a30
+	../../support/nfs/libnfs.a \
e19a30
+	$(LIBEVENT) \
e19a30
+	$(RPCSECGSS_LIBS) \
e19a30
+	$(KRBLIBS) \
e19a30
+	$(GSSAPI_LIBS) \
e19a30
+	$(LIBTIRPC)
e19a30
 
e19a30
-gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
e19a30
-	      $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS)
e19a30
+gssd_LDFLAGS = \
e19a30
+	$(KRBLDFLAGS)
e19a30
+
e19a30
+gssd_CFLAGS = \
e19a30
+	$(AM_CFLAGS) \
e19a30
+	$(CFLAGS) \
e19a30
+	$(RPCSECGSS_CFLAGS) \
e19a30
+	$(KRBCFLAGS) \
e19a30
+	$(GSSAPI_CFLAGS)
e19a30
 
e19a30
 svcgssd_SOURCES = \
e19a30
 	$(COMMON_SRCS) \
e19a30
diff -up nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig nfs-utils-1.3.0/utils/gssd/svcgssd.c
e19a30
--- nfs-utils-1.3.0/utils/gssd/svcgssd.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/gssd/svcgssd.c	2016-04-15 11:42:38.372938482 -0400
e19a30
@@ -62,8 +62,6 @@
e19a30
 #include "gss_util.h"
e19a30
 #include "err_util.h"
e19a30
 
e19a30
-static int pipefds[2] = { -1, -1 };
e19a30
-
e19a30
 void
e19a30
 sig_die(int signal)
e19a30
 {
e19a30
@@ -137,6 +135,13 @@ main(int argc, char *argv[])
e19a30
 	if (verbosity && rpc_verbosity == 0)
e19a30
 		rpc_verbosity = verbosity;
e19a30
 	authgss_set_debug_level(rpc_verbosity);
e19a30
+#elif HAVE_LIBTIRPC_SET_DEBUG
e19a30
+        /*
e19a30
+	 * Only set the libtirpc debug level if explicitly requested via -r...
e19a30
+	 * svcgssd is chatty enough as it is.
e19a30
+	 */
e19a30
+        if (rpc_verbosity > 0)
e19a30
+                libtirpc_set_debug(progname, rpc_verbosity, fg);
e19a30
 #else
e19a30
 	if (rpc_verbosity > 0)
e19a30
 		printerr(0, "Warning: rpcsec_gss library does not "
e19a30
@@ -157,8 +162,7 @@ main(int argc, char *argv[])
e19a30
 		exit(1);
e19a30
 	}
e19a30
 
e19a30
-	if (!fg)
e19a30
-		mydaemon(0, 0, pipefds);
e19a30
+	daemon_init(fg);
e19a30
 
e19a30
 	signal(SIGINT, sig_die);
e19a30
 	signal(SIGTERM, sig_die);
e19a30
@@ -187,8 +191,7 @@ main(int argc, char *argv[])
e19a30
 		}
e19a30
 	}
e19a30
 
e19a30
-	if (!fg)
e19a30
-		release_parent(pipefds);
e19a30
+	daemon_ready();
e19a30
 
e19a30
 	nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
e19a30
 	gssd_run();
e19a30
diff -up nfs-utils-1.3.0/utils/idmapd/idmapd.c.orig nfs-utils-1.3.0/utils/idmapd/idmapd.c
e19a30
--- nfs-utils-1.3.0/utils/idmapd/idmapd.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/idmapd/idmapd.c	2016-04-15 11:42:38.373938502 -0400
e19a30
@@ -164,7 +164,6 @@ static char pipefsdir[PATH_MAX];
e19a30
 static char *nobodyuser, *nobodygroup;
e19a30
 static uid_t nobodyuid;
e19a30
 static gid_t nobodygid;
e19a30
-static int pipefds[2] = { -1, -1 };
e19a30
 
e19a30
 /* Used by conffile.c in libnfs.a */
e19a30
 char *conf_path;
e19a30
@@ -302,8 +301,7 @@ main(int argc, char **argv)
e19a30
 	if (nfs4_init_name_mapping(conf_path))
e19a30
 		errx(1, "Unable to create name to user id mappings.");
e19a30
 
e19a30
-	if (!fg)
e19a30
-		mydaemon(0, 0, pipefds);
e19a30
+	daemon_init(fg);
e19a30
 
e19a30
 	event_init();
e19a30
 
e19a30
@@ -380,7 +378,7 @@ main(int argc, char **argv)
e19a30
 	if (nfsdret != 0 && fd == 0)
e19a30
 		xlog_err("main: Neither NFS client nor NFSd found");
e19a30
 
e19a30
-	release_parent(pipefds);
e19a30
+	daemon_ready();
e19a30
 
e19a30
 	if (event_dispatch() < 0)
e19a30
 		xlog_err("main: event_dispatch returns errno %d (%s)",
e19a30
diff -up nfs-utils-1.3.0/utils/statd/statd.c.orig nfs-utils-1.3.0/utils/statd/statd.c
e19a30
--- nfs-utils-1.3.0/utils/statd/statd.c.orig	2014-03-25 11:12:07.000000000 -0400
e19a30
+++ nfs-utils-1.3.0/utils/statd/statd.c	2016-04-15 11:42:38.373938502 -0400
e19a30
@@ -248,13 +248,12 @@ int main (int argc, char **argv)
e19a30
 	int nlm_udp = 0, nlm_tcp = 0;
e19a30
 	struct rlimit rlim;
e19a30
 
e19a30
-	int pipefds[2] = { -1, -1};
e19a30
-	char status;
e19a30
-
e19a30
 	/* Default: daemon mode, no other options */
e19a30
 	run_mode = 0;
e19a30
-	xlog_stderr(0);
e19a30
-	xlog_syslog(1);
e19a30
+
e19a30
+	/* Log to stderr if there's an error during startup */
e19a30
+	xlog_stderr(1);
e19a30
+	xlog_syslog(0);
e19a30
 
e19a30
 	/* Set the basename */
e19a30
 	if ((name_p = strrchr(argv[0],'/')) != NULL) {
e19a30
@@ -394,52 +393,17 @@ int main (int argc, char **argv)
e19a30
 		simulator (--argc, ++argv);	/* simulator() does exit() */
e19a30
 #endif
e19a30
 
e19a30
-	if (!(run_mode & MODE_NODAEMON)) {
e19a30
-		int tempfd;
e19a30
-
e19a30
-		if (pipe(pipefds)<0) {
e19a30
-			perror("statd: unable to create pipe");
e19a30
-			exit(1);
e19a30
-		}
e19a30
-		if ((pid = fork ()) < 0) {
e19a30
-			perror ("statd: Could not fork");
e19a30
-			exit (1);
e19a30
-		} else if (pid != 0) {
e19a30
-			/* Parent.
e19a30
-			 * Wait for status from child.
e19a30
-			 */
e19a30
-			close(pipefds[1]);
e19a30
-			if (read(pipefds[0], &status, 1) != 1)
e19a30
-				exit(1);
e19a30
-			exit (0);
e19a30
-		}
e19a30
-		/* Child.	*/
e19a30
-		close(pipefds[0]);
e19a30
-		setsid ();
e19a30
-
e19a30
-		while (pipefds[1] <= 2) {
e19a30
-			pipefds[1] = dup(pipefds[1]);
e19a30
-			if (pipefds[1]<0) {
e19a30
-				perror("statd: dup");
e19a30
-				exit(1);
e19a30
-			}
e19a30
-		}
e19a30
-		tempfd = open("/dev/null", O_RDWR);
e19a30
-		dup2(tempfd, 0);
e19a30
-		dup2(tempfd, 1);
e19a30
-		dup2(tempfd, 2);
e19a30
-		dup2(pipefds[1], 3);
e19a30
-		pipefds[1] = 3;
e19a30
-		closeall(4);
e19a30
-	}
e19a30
-
e19a30
-	/* Child. */
e19a30
+	daemon_init((run_mode & MODE_NODAEMON));
e19a30
 
e19a30
 	if (run_mode & MODE_LOG_STDERR) {
e19a30
 		xlog_syslog(0);
e19a30
 		xlog_stderr(1);
e19a30
 		xlog_config(D_ALL, 1);
e19a30
+	} else {
e19a30
+		xlog_syslog(1);
e19a30
+		xlog_stderr(0);
e19a30
 	}
e19a30
+
e19a30
 	xlog_open(name_p);
e19a30
 	xlog(L_NOTICE, "Version " VERSION " starting");
e19a30
 
e19a30
@@ -512,16 +476,8 @@ int main (int argc, char **argv)
e19a30
 	}
e19a30
 	atexit(statd_unregister);
e19a30
 
e19a30
-	/* If we got this far, we have successfully started, so notify parent */
e19a30
-	if (pipefds[1] > 0) {
e19a30
-		status = 0;
e19a30
-		if (write(pipefds[1], &status, 1) != 1) {
e19a30
-			xlog_warn("writing to parent pipe failed: errno %d (%s)\n",
e19a30
-				errno, strerror(errno));
e19a30
-		}
e19a30
-		close(pipefds[1]);
e19a30
-		pipefds[1] = -1;
e19a30
-	}
e19a30
+	/* If we got this far, we have successfully started */
e19a30
+	daemon_ready();
e19a30
 
e19a30
 	for (;;) {
e19a30
 		/*