Blame SOURCES/nfs-utils-2.3.3-gssd-multithread-updates.patch

d50f3a
diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4
d50f3a
index b5ac00ff..0ebcb524 100644
d50f3a
--- a/aclocal/libevent.m4
d50f3a
+++ b/aclocal/libevent.m4
d50f3a
@@ -4,9 +4,13 @@ AC_DEFUN([AC_LIBEVENT], [
d50f3a
   dnl Check for libevent, but do not add -levent to LIBS
d50f3a
   AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent],
d50f3a
                [AC_MSG_ERROR([libevent not found.])])
d50f3a
+  AC_CHECK_LIB([event_core], [event_base_dispatch], [LIBEVENT=-levent_core],
d50f3a
+  	[AC_MSG_ERROR([libevent2 not found.])])
d50f3a
   AC_SUBST(LIBEVENT)
d50f3a
 
d50f3a
   AC_CHECK_HEADERS([event.h], ,
d50f3a
                    [AC_MSG_ERROR([libevent headers not found.])])
d50f3a
+  AC_CHECK_HEADERS([event2/event.h], ,
d50f3a
+                   [AC_MSG_ERROR([libevent headers not found.])])
d50f3a
 
d50f3a
 ])dnl
d50f3a
diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c
d50f3a
index 2a7f3a13..982b96f4 100644
d50f3a
--- a/utils/gssd/gss_names.c
d50f3a
+++ b/utils/gssd/gss_names.c
d50f3a
@@ -110,10 +110,12 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
d50f3a
 	/* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
d50f3a
 	 * an NT_HOSTBASED_SERVICE name */
d50f3a
 	if (g_OID_equal(&krb5oid, mech)) {
d50f3a
-		if (get_krb5_hostbased_name(&name, &cname) == 0)
d50f3a
-			*hostbased_name = cname;
d50f3a
+		if (get_krb5_hostbased_name(&name, &cname) != 0)
d50f3a
+			goto out_rel_buf;
d50f3a
+		*hostbased_name = cname;
d50f3a
 	} else {
d50f3a
 		printerr(1, "WARNING: unknown/unsupport mech OID\n");
d50f3a
+		goto out_rel_buf;
d50f3a
 	}
d50f3a
 
d50f3a
 	res = 0;
d50f3a
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
d50f3a
index af66ed62..6f461fdf 100644
d50f3a
--- a/utils/gssd/gssd.c
d50f3a
+++ b/utils/gssd/gssd.c
d50f3a
@@ -64,7 +64,7 @@
d50f3a
 #include <fcntl.h>
d50f3a
 #include <dirent.h>
d50f3a
 #include <netdb.h>
d50f3a
-#include <event.h>
d50f3a
+#include <event2/event.h>
d50f3a
 
d50f3a
 #include "gssd.h"
d50f3a
 #include "err_util.h"
d50f3a
@@ -77,7 +77,7 @@ static char *pipefs_path = GSSD_PIPEFS_DIR;
d50f3a
 static DIR *pipefs_dir;
d50f3a
 static int pipefs_fd;
d50f3a
 static int inotify_fd;
d50f3a
-struct event inotify_ev;
d50f3a
+struct event *inotify_ev;
d50f3a
 
d50f3a
 char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE;
d50f3a
 char **ccachesearch;
d50f3a
@@ -90,9 +90,9 @@ char *ccachedir = NULL;
d50f3a
 /* Avoid DNS reverse lookups on server names */
d50f3a
 static bool avoid_dns = true;
d50f3a
 static bool use_gssproxy = false;
d50f3a
-int thread_started = false;
d50f3a
-pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER;
d50f3a
-pthread_cond_t pcond = PTHREAD_COND_INITIALIZER;
d50f3a
+pthread_mutex_t clp_lock = PTHREAD_MUTEX_INITIALIZER;
d50f3a
+static bool signal_received = false;
d50f3a
+static struct event_base *evbase = NULL;
d50f3a
 
d50f3a
 TAILQ_HEAD(topdir_list_head, topdir) topdir_list;
d50f3a
 
d50f3a
@@ -359,20 +359,28 @@ out:
d50f3a
 	free(port);
d50f3a
 }
d50f3a
 
d50f3a
+/* Actually frees clp and fields that might be used from other
d50f3a
+ * threads if was last reference.
d50f3a
+ */
d50f3a
 static void
d50f3a
-gssd_destroy_client(struct clnt_info *clp)
d50f3a
+gssd_free_client(struct clnt_info *clp)
d50f3a
 {
d50f3a
-	if (clp->krb5_fd >= 0) {
d50f3a
+	int refcnt;
d50f3a
+
d50f3a
+	pthread_mutex_lock(&clp_lock);
d50f3a
+	refcnt = --clp->refcount;
d50f3a
+	pthread_mutex_unlock(&clp_lock);
d50f3a
+	if (refcnt > 0)
d50f3a
+		return;
d50f3a
+
d50f3a
+	printerr(3, "freeing client %s\n", clp->relpath);
d50f3a
+
d50f3a
+	if (clp->krb5_fd >= 0)
d50f3a
 		close(clp->krb5_fd);
d50f3a
-		event_del(&clp->krb5_ev);
d50f3a
-	}
d50f3a
 
d50f3a
-	if (clp->gssd_fd >= 0) {
d50f3a
+	if (clp->gssd_fd >= 0)
d50f3a
 		close(clp->gssd_fd);
d50f3a
-		event_del(&clp->gssd_ev);
d50f3a
-	}
d50f3a
 
d50f3a
-	inotify_rm_watch(inotify_fd, clp->wd);
d50f3a
 	free(clp->relpath);
d50f3a
 	free(clp->servicename);
d50f3a
 	free(clp->servername);
d50f3a
@@ -380,6 +388,30 @@ gssd_destroy_client(struct clnt_info *clp)
d50f3a
 	free(clp);
d50f3a
 }
d50f3a
 
d50f3a
+/* Called when removing from clnt_list to tear down event handling.
d50f3a
+ * Will then free clp if was last reference.
d50f3a
+ */
d50f3a
+static void
d50f3a
+gssd_destroy_client(struct clnt_info *clp)
d50f3a
+{
d50f3a
+	printerr(3, "destroying client %s\n", clp->relpath);
d50f3a
+
d50f3a
+	if (clp->krb5_ev) {
d50f3a
+		event_del(clp->krb5_ev);
d50f3a
+		event_free(clp->krb5_ev);
d50f3a
+		clp->krb5_ev = NULL;
d50f3a
+	}
d50f3a
+
d50f3a
+	if (clp->gssd_ev) {
d50f3a
+		event_del(clp->gssd_ev);
d50f3a
+		event_free(clp->gssd_ev);
d50f3a
+		clp->gssd_ev = NULL;
d50f3a
+	}
d50f3a
+
d50f3a
+	inotify_rm_watch(inotify_fd, clp->wd);
d50f3a
+	gssd_free_client(clp);
d50f3a
+}
d50f3a
+
d50f3a
 static void gssd_scan(void);
d50f3a
 
d50f3a
 static int
d50f3a
@@ -416,11 +448,21 @@ static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp)
d50f3a
 	info = malloc(sizeof(struct clnt_upcall_info));
d50f3a
 	if (info == NULL)
d50f3a
 		return NULL;
d50f3a
+
d50f3a
+	pthread_mutex_lock(&clp_lock);
d50f3a
+	clp->refcount++;
d50f3a
+	pthread_mutex_unlock(&clp_lock);
d50f3a
 	info->clp = clp;
d50f3a
 
d50f3a
 	return info;
d50f3a
 }
d50f3a
 
d50f3a
+void free_upcall_info(struct clnt_upcall_info *info)
d50f3a
+{
d50f3a
+	gssd_free_client(info->clp);
d50f3a
+	free(info);
d50f3a
+}
d50f3a
+
d50f3a
 /* For each upcall read the upcall info into the buffer, then create a
d50f3a
  * thread in a detached state so that resources are released back into
d50f3a
  * the system without the need for a join.
d50f3a
@@ -438,13 +480,13 @@ gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
d50f3a
 	info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf));
d50f3a
 	if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') {
d50f3a
 		printerr(0, "WARNING: %s: failed reading request\n", __func__);
d50f3a
-		free(info);
d50f3a
+		free_upcall_info(info);
d50f3a
 		return;
d50f3a
 	}
d50f3a
 	info->lbuf[info->lbuflen-1] = 0;
d50f3a
 
d50f3a
 	if (start_upcall_thread(handle_gssd_upcall, info))
d50f3a
-		free(info);
d50f3a
+		free_upcall_info(info);
d50f3a
 }
d50f3a
 
d50f3a
 static void
d50f3a
@@ -461,12 +503,12 @@ gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
d50f3a
 			sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) {
d50f3a
 		printerr(0, "WARNING: %s: failed reading uid from krb5 "
d50f3a
 			 "upcall pipe: %s\n", __func__, strerror(errno));
d50f3a
-		free(info);
d50f3a
+		free_upcall_info(info);
d50f3a
 		return;
d50f3a
 	}
d50f3a
 
d50f3a
 	if (start_upcall_thread(handle_krb5_upcall, info))
d50f3a
-		free(info);
d50f3a
+		free_upcall_info(info);
d50f3a
 }
d50f3a
 
d50f3a
 static struct clnt_info *
d50f3a
@@ -501,6 +543,7 @@ gssd_get_clnt(struct topdir *tdi, const char *name)
d50f3a
 	clp->name = clp->relpath + strlen(tdi->name) + 1;
d50f3a
 	clp->krb5_fd = -1;
d50f3a
 	clp->gssd_fd = -1;
d50f3a
+	clp->refcount = 1;
d50f3a
 
d50f3a
 	TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list);
d50f3a
 	return clp;
d50f3a
@@ -535,15 +578,15 @@ gssd_scan_clnt(struct clnt_info *clp)
d50f3a
 		clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK);
d50f3a
 
d50f3a
 	if (gssd_was_closed && clp->gssd_fd >= 0) {
d50f3a
-		event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST,
d50f3a
-			  gssd_clnt_gssd_cb, clp);
d50f3a
-		event_add(&clp->gssd_ev, NULL);
d50f3a
+		clp->gssd_ev = event_new(evbase, clp->gssd_fd, EV_READ | EV_PERSIST,
d50f3a
+					 gssd_clnt_gssd_cb, clp);
d50f3a
+		event_add(clp->gssd_ev, NULL);
d50f3a
 	}
d50f3a
 
d50f3a
 	if (krb5_was_closed && clp->krb5_fd >= 0) {
d50f3a
-		event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST,
d50f3a
-			  gssd_clnt_krb5_cb, clp);
d50f3a
-		event_add(&clp->krb5_ev, NULL);
d50f3a
+		clp->krb5_ev = event_new(evbase, clp->krb5_fd, EV_READ | EV_PERSIST,
d50f3a
+					 gssd_clnt_krb5_cb, clp);
d50f3a
+		event_add(clp->krb5_ev, NULL);
d50f3a
 	}
d50f3a
 
d50f3a
 	if (clp->krb5_fd == -1 && clp->gssd_fd == -1)
d50f3a
@@ -649,7 +692,7 @@ gssd_scan_topdir(const char *name)
d50f3a
 		if (clp->scanned)
d50f3a
 			continue;
d50f3a
 
d50f3a
-		printerr(3, "destroying client %s\n", clp->relpath);
d50f3a
+		printerr(3, "orphaned client %s\n", clp->relpath);
d50f3a
 		saveprev = clp->list.tqe_prev;
d50f3a
 		TAILQ_REMOVE(&tdi->clnt_list, clp, list);
d50f3a
 		gssd_destroy_client(clp);
d50f3a
@@ -746,12 +789,16 @@ gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotif
d50f3a
 	} else if (ev->mask & IN_DELETE) {
d50f3a
 		if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) {
d50f3a
 			close(clp->gssd_fd);
d50f3a
-			event_del(&clp->gssd_ev);
d50f3a
+			event_del(clp->gssd_ev);
d50f3a
+			event_free(clp->gssd_ev);
d50f3a
+			clp->gssd_ev = NULL;
d50f3a
 			clp->gssd_fd = -1;
d50f3a
 
d50f3a
 		} else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) {
d50f3a
 			close(clp->krb5_fd);
d50f3a
-			event_del(&clp->krb5_ev);
d50f3a
+			event_del(clp->krb5_ev);
d50f3a
+			event_free(clp->krb5_ev);
d50f3a
+			clp->krb5_ev = NULL;
d50f3a
 			clp->krb5_fd = -1;
d50f3a
 		}
d50f3a
 
d50f3a
@@ -824,10 +871,15 @@ found:
d50f3a
 static void
d50f3a
 sig_die(int signal)
d50f3a
 {
d50f3a
-	if (root_uses_machine_creds)
d50f3a
-		gssd_destroy_krb5_machine_creds();
d50f3a
+	if (signal_received) {
d50f3a
+		gssd_destroy_krb5_principals(root_uses_machine_creds);
d50f3a
+		printerr(1, "forced exiting on signal %d\n", signal);
d50f3a
+		exit(0);
d50f3a
+	}
d50f3a
+
d50f3a
+	signal_received = true;
d50f3a
 	printerr(1, "exiting on signal %d\n", signal);
d50f3a
-	exit(0);
d50f3a
+	event_base_loopexit(evbase, NULL);
d50f3a
 }
d50f3a
 
d50f3a
 static void
d50f3a
@@ -884,9 +936,10 @@ main(int argc, char *argv[])
d50f3a
 	int rpc_verbosity = 0;
d50f3a
 	int opt;
d50f3a
 	int i;
d50f3a
+	int rc;
d50f3a
 	extern char *optarg;
d50f3a
 	char *progname;
d50f3a
-	struct event sighup_ev;
d50f3a
+	struct event *sighup_ev;
d50f3a
 
d50f3a
 	read_gss_conf();
d50f3a
 
d50f3a
@@ -1025,7 +1078,11 @@ main(int argc, char *argv[])
d50f3a
 	if (gssd_check_mechs() != 0)
d50f3a
 		errx(1, "Problem with gssapi library");
d50f3a
 
d50f3a
-	event_init();
d50f3a
+	evbase = event_base_new();
d50f3a
+	if (!evbase) {
d50f3a
+		printerr(0, "ERROR: failed to create event base\n");
d50f3a
+		exit(EXIT_FAILURE);
d50f3a
+	}
d50f3a
 
d50f3a
 	pipefs_dir = opendir(pipefs_path);
d50f3a
 	if (!pipefs_dir) {
d50f3a
@@ -1047,18 +1104,43 @@ main(int argc, char *argv[])
d50f3a
 
d50f3a
 	signal(SIGINT, sig_die);
d50f3a
 	signal(SIGTERM, sig_die);
d50f3a
-	signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL);
d50f3a
-	signal_add(&sighup_ev, NULL);
d50f3a
-	event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL);
d50f3a
-	event_add(&inotify_ev, NULL);
d50f3a
+	sighup_ev = evsignal_new(evbase, SIGHUP, gssd_scan_cb, NULL);
d50f3a
+	evsignal_add(sighup_ev, NULL);
d50f3a
+	inotify_ev = event_new(evbase, inotify_fd, EV_READ | EV_PERSIST,
d50f3a
+			       gssd_inotify_cb, NULL);
d50f3a
+	event_add(inotify_ev, NULL);
d50f3a
 
d50f3a
 	TAILQ_INIT(&topdir_list);
d50f3a
 	gssd_scan();
d50f3a
 	daemon_ready();
d50f3a
 
d50f3a
-	event_dispatch();
d50f3a
+	rc = event_base_dispatch(evbase);
d50f3a
 
d50f3a
-	printerr(0, "ERROR: event_dispatch() returned!\n");
d50f3a
-	return EXIT_FAILURE;
d50f3a
-}
d50f3a
+	printerr(0, "event_dispatch() returned %i!\n", rc);
d50f3a
+
d50f3a
+	gssd_destroy_krb5_principals(root_uses_machine_creds);
d50f3a
+
d50f3a
+	while (!TAILQ_EMPTY(&topdir_list)) {
d50f3a
+		struct topdir *tdi = TAILQ_FIRST(&topdir_list);
d50f3a
+		TAILQ_REMOVE(&topdir_list, tdi, list);
d50f3a
+		while (!TAILQ_EMPTY(&tdi->clnt_list)) {
d50f3a
+			struct clnt_info *clp = TAILQ_FIRST(&tdi->clnt_list);
d50f3a
+			TAILQ_REMOVE(&tdi->clnt_list, clp, list);
d50f3a
+			gssd_destroy_client(clp);
d50f3a
+		}
d50f3a
+		free(tdi);
d50f3a
+	}
d50f3a
+
d50f3a
+	event_free(inotify_ev);
d50f3a
+	event_free(sighup_ev);
d50f3a
+	event_base_free(evbase);
d50f3a
+
d50f3a
+	close(inotify_fd);
d50f3a
+	close(pipefs_fd);
d50f3a
+	closedir(pipefs_dir);
d50f3a
 
d50f3a
+	free(preferred_realm);
d50f3a
+	free(ccachesearch);
d50f3a
+
d50f3a
+	return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
d50f3a
+}
d50f3a
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
d50f3a
index f4f59754..1e8c58d4 100644
d50f3a
--- a/utils/gssd/gssd.h
d50f3a
+++ b/utils/gssd/gssd.h
d50f3a
@@ -62,13 +62,10 @@ extern int			root_uses_machine_creds;
d50f3a
 extern unsigned int 		context_timeout;
d50f3a
 extern unsigned int rpc_timeout;
d50f3a
 extern char			*preferred_realm;
d50f3a
-extern pthread_mutex_t ple_lock;
d50f3a
-extern pthread_cond_t pcond;
d50f3a
-extern pthread_mutex_t pmutex;
d50f3a
-extern int thread_started;
d50f3a
 
d50f3a
 struct clnt_info {
d50f3a
 	TAILQ_ENTRY(clnt_info)	list;
d50f3a
+	int			refcount;
d50f3a
 	int			wd;
d50f3a
 	bool			scanned;
d50f3a
 	char			*name;
d50f3a
@@ -79,9 +76,9 @@ struct clnt_info {
d50f3a
 	int			vers;
d50f3a
 	char			*protocol;
d50f3a
 	int			krb5_fd;
d50f3a
-	struct event		krb5_ev;
d50f3a
+	struct event		*krb5_ev;
d50f3a
 	int			gssd_fd;
d50f3a
-	struct event		gssd_ev;
d50f3a
+	struct event		*gssd_ev;
d50f3a
 	struct			sockaddr_storage addr;
d50f3a
 };
d50f3a
 
d50f3a
@@ -94,6 +91,7 @@ struct clnt_upcall_info {
d50f3a
 
d50f3a
 void handle_krb5_upcall(struct clnt_upcall_info *clp);
d50f3a
 void handle_gssd_upcall(struct clnt_upcall_info *clp);
d50f3a
+void free_upcall_info(struct clnt_upcall_info *info);
d50f3a
 
d50f3a
 
d50f3a
 #endif /* _RPC_GSSD_H_ */
d50f3a
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
d50f3a
index bfcf3f09..ae3ebe81 100644
d50f3a
--- a/utils/gssd/gssd_proc.c
d50f3a
+++ b/utils/gssd/gssd_proc.c
d50f3a
@@ -149,9 +149,10 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
d50f3a
 	char    *buf = NULL, *p = NULL, *end = NULL;
d50f3a
 	unsigned int timeout = context_timeout;
d50f3a
 	unsigned int buf_size = 0;
d50f3a
+	pthread_t tid = pthread_self();
d50f3a
 
d50f3a
-	printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n",
d50f3a
-		lifetime_rec, acceptor->length, acceptor->value);
d50f3a
+	printerr(2, "do_downcall(0x%x): lifetime_rec=%u acceptor=%.*s\n",
d50f3a
+		tid, lifetime_rec, acceptor->length, acceptor->value);
d50f3a
 	buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
d50f3a
 		sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
d50f3a
 		sizeof(context_token->length) + context_token->length +
d50f3a
@@ -177,7 +178,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
d50f3a
 	return;
d50f3a
 out_err:
d50f3a
 	free(buf);
d50f3a
-	printerr(1, "Failed to write downcall!\n");
d50f3a
+	printerr(1, "do_downcall(0x%x): Failed to write downcall!\n", tid);
d50f3a
 	return;
d50f3a
 }
d50f3a
 
d50f3a
@@ -231,7 +232,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen,
d50f3a
 	switch (sa->sa_family) {
d50f3a
 	case AF_INET:
d50f3a
 		if (s4->sin_port != 0) {
d50f3a
-			printerr(2, "DEBUG: port already set to %d\n",
d50f3a
+			printerr(4, "DEBUG: port already set to %d\n",
d50f3a
 				 ntohs(s4->sin_port));
d50f3a
 			return 1;
d50f3a
 		}
d50f3a
@@ -239,7 +240,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen,
d50f3a
 #ifdef IPV6_SUPPORTED
d50f3a
 	case AF_INET6:
d50f3a
 		if (s6->sin6_port != 0) {
d50f3a
-			printerr(2, "DEBUG: port already set to %d\n",
d50f3a
+			printerr(4, "DEBUG: port already set to %d\n",
d50f3a
 				 ntohs(s6->sin6_port));
d50f3a
 			return 1;
d50f3a
 		}
d50f3a
@@ -544,7 +545,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid,
d50f3a
 		uid, tgtname);
d50f3a
 
d50f3a
 	do {
d50f3a
-		gssd_refresh_krb5_machine_credential(clp->servername, NULL,
d50f3a
+		gssd_refresh_krb5_machine_credential(clp->servername,
d50f3a
 						     service, srchost);
d50f3a
 	/*
d50f3a
 	 * Get a list of credential cache names and try each
d50f3a
@@ -726,7 +727,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info)
d50f3a
 	printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath);
d50f3a
 
d50f3a
 	process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL);
d50f3a
-	free(info);
d50f3a
+	free_upcall_info(info);
d50f3a
 }
d50f3a
 
d50f3a
 void
d50f3a
@@ -743,8 +744,10 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
d50f3a
 	char			*enctypes = NULL;
d50f3a
 	char			*upcall_str;
d50f3a
 	char			*pbuf = info->lbuf;
d50f3a
+	pthread_t tid = pthread_self();
d50f3a
 
d50f3a
-	printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
d50f3a
+	printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid, 
d50f3a
+		info->lbuf, clp->relpath);
d50f3a
 
d50f3a
 	upcall_str = strdup(info->lbuf);
d50f3a
 	if (upcall_str == NULL) {
d50f3a
@@ -826,6 +829,6 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
d50f3a
 out:
d50f3a
 	free(upcall_str);
d50f3a
 out_nomem:
d50f3a
-	free(info);
d50f3a
+	free_upcall_info(info);
d50f3a
 	return;
d50f3a
 }
d50f3a
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
d50f3a
index 26e51edf..d675c3a4 100644
d50f3a
--- a/utils/gssd/krb5_util.c
d50f3a
+++ b/utils/gssd/krb5_util.c
d50f3a
@@ -126,9 +126,28 @@
d50f3a
 #include "gss_util.h"
d50f3a
 #include "krb5_util.h"
d50f3a
 
d50f3a
+/*
d50f3a
+ * List of principals from our keytab that we
d50f3a
+ * will try to use to obtain credentials
d50f3a
+ * (known as a principal list entry (ple))
d50f3a
+ */
d50f3a
+struct gssd_k5_kt_princ {
d50f3a
+	struct gssd_k5_kt_princ *next;
d50f3a
+	// Only protect against deletion, not modification
d50f3a
+	int refcount;
d50f3a
+	// Only set during creation in new_ple()
d50f3a
+	krb5_principal princ;
d50f3a
+	char *realm;
d50f3a
+	// Modified during usage by gssd_get_single_krb5_cred()
d50f3a
+	char *ccname;
d50f3a
+	krb5_timestamp endtime;
d50f3a
+};
d50f3a
+
d50f3a
+
d50f3a
 /* Global list of principals/cache file names for machine credentials */
d50f3a
-struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
d50f3a
-pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER;
d50f3a
+static struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
d50f3a
+/* This mutex protects list modification & ple->ccname */
d50f3a
+static pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER;
d50f3a
 
d50f3a
 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
d50f3a
 int limit_to_legacy_enctypes = 0;
d50f3a
@@ -146,6 +165,18 @@ static int gssd_get_single_krb5_cred(krb5_context context,
d50f3a
 static int query_krb5_ccache(const char* cred_cache, char **ret_princname,
d50f3a
 		char **ret_realm);
d50f3a
 
d50f3a
+static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple)
d50f3a
+{
d50f3a
+	if (--ple->refcount)
d50f3a
+		return;
d50f3a
+
d50f3a
+	printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", ple->ccname, ple->realm);
d50f3a
+	krb5_free_principal(context, ple->princ);
d50f3a
+	free(ple->ccname);
d50f3a
+	free(ple->realm);
d50f3a
+	free(ple);
d50f3a
+}
d50f3a
+
d50f3a
 /*
d50f3a
  * Called from the scandir function to weed out potential krb5
d50f3a
  * credentials cache files
d50f3a
@@ -352,12 +383,15 @@ gssd_get_single_krb5_cred(krb5_context context,
d50f3a
 	 * 300 because clock skew must be within 300sec for kerberos
d50f3a
 	 */
d50f3a
 	now += 300;
d50f3a
+	pthread_mutex_lock(&ple_lock);
d50f3a
 	if (ple->ccname && ple->endtime > now && !nocache) {
d50f3a
 		printerr(3, "INFO: Credentials in CC '%s' are good until %d\n",
d50f3a
 			 ple->ccname, ple->endtime);
d50f3a
 		code = 0;
d50f3a
+		pthread_mutex_unlock(&ple_lock);
d50f3a
 		goto out;
d50f3a
 	}
d50f3a
+	pthread_mutex_unlock(&ple_lock);
d50f3a
 
d50f3a
 	if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) {
d50f3a
 		printerr(0, "ERROR: Unable to get keytab name in "
d50f3a
@@ -410,6 +444,7 @@ gssd_get_single_krb5_cred(krb5_context context,
d50f3a
 	 * Initialize cache file which we're going to be using
d50f3a
 	 */
d50f3a
 
d50f3a
+	pthread_mutex_lock(&ple_lock);
d50f3a
 	if (use_memcache)
d50f3a
 	    cache_type = "MEMORY";
d50f3a
 	else
d50f3a
@@ -419,15 +454,18 @@ gssd_get_single_krb5_cred(krb5_context context,
d50f3a
 		ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX,
d50f3a
 		GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
d50f3a
 	ple->endtime = my_creds.times.endtime;
d50f3a
-	if (ple->ccname != NULL)
d50f3a
+	if (ple->ccname == NULL || strcmp(ple->ccname, cc_name) != 0) {
d50f3a
 		free(ple->ccname);
d50f3a
-	ple->ccname = strdup(cc_name);
d50f3a
-	if (ple->ccname == NULL) {
d50f3a
-		printerr(0, "ERROR: no storage to duplicate credentials "
d50f3a
-			    "cache name '%s'\n", cc_name);
d50f3a
-		code = ENOMEM;
d50f3a
-		goto out;
d50f3a
+		ple->ccname = strdup(cc_name);
d50f3a
+		if (ple->ccname == NULL) {
d50f3a
+			printerr(0, "ERROR: no storage to duplicate credentials "
d50f3a
+				    "cache name '%s'\n", cc_name);
d50f3a
+			code = ENOMEM;
d50f3a
+			pthread_mutex_unlock(&ple_lock);
d50f3a
+			goto out;
d50f3a
+		}
d50f3a
 	}
d50f3a
+	pthread_mutex_unlock(&ple_lock);
d50f3a
 	if ((code = krb5_cc_resolve(context, cc_name, &ccache))) {
d50f3a
 		k5err = gssd_k5_err_msg(context, code);
d50f3a
 		printerr(0, "ERROR: %s while opening credential cache '%s'\n",
d50f3a
@@ -465,6 +503,7 @@ gssd_get_single_krb5_cred(krb5_context context,
d50f3a
 
d50f3a
 /*
d50f3a
  * Given a principal, find a matching ple structure
d50f3a
+ * Called with mutex held
d50f3a
  */
d50f3a
 static struct gssd_k5_kt_princ *
d50f3a
 find_ple_by_princ(krb5_context context, krb5_principal princ)
d50f3a
@@ -481,6 +520,7 @@ find_ple_by_princ(krb5_context context, krb5_principal princ)
d50f3a
 
d50f3a
 /*
d50f3a
  * Create, initialize, and add a new ple structure to the global list
d50f3a
+ * Called with mutex held
d50f3a
  */
d50f3a
 static struct gssd_k5_kt_princ *
d50f3a
 new_ple(krb5_context context, krb5_principal princ)
d50f3a
@@ -532,6 +572,7 @@ new_ple(krb5_context context, krb5_principal princ)
d50f3a
 			p->next = ple;
d50f3a
 	}
d50f3a
 
d50f3a
+	ple->refcount = 1;
d50f3a
 	return ple;
d50f3a
 outerr:
d50f3a
 	if (ple) {
d50f3a
@@ -550,13 +591,14 @@ get_ple_by_princ(krb5_context context, krb5_principal princ)
d50f3a
 {
d50f3a
 	struct gssd_k5_kt_princ *ple;
d50f3a
 
d50f3a
-	/* Need to serialize list if we ever become multi-threaded! */
d50f3a
-
d50f3a
 	pthread_mutex_lock(&ple_lock);
d50f3a
 	ple = find_ple_by_princ(context, princ);
d50f3a
 	if (ple == NULL) {
d50f3a
 		ple = new_ple(context, princ);
d50f3a
 	}
d50f3a
+	if (ple != NULL) {
d50f3a
+		ple->refcount++;
d50f3a
+	}
d50f3a
 	pthread_mutex_unlock(&ple_lock);
d50f3a
 
d50f3a
 	return ple;
d50f3a
@@ -721,6 +763,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
d50f3a
 				retval = ENOMEM;
d50f3a
 				k5_free_kt_entry(context, kte);
d50f3a
 			} else {
d50f3a
+				release_ple(context, ple);
d50f3a
+				ple = NULL;
d50f3a
 				retval = 0;
d50f3a
 				*found = 1;
d50f3a
 			}
d50f3a
@@ -796,12 +840,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
d50f3a
 	/* Compute the active directory machine name HOST$ */
d50f3a
 	krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name", 
d50f3a
 		notsetstr, &adhostoverride);
d50f3a
-	if (strcmp(adhostoverride, notsetstr) != 0) {
d50f3a
-	        printerr (1, 
d50f3a
-				"AD host string overridden with \"%s\" from appdefaults\n", 
d50f3a
-				adhostoverride);
d50f3a
-	        /* No overflow: Windows cannot handle strings longer than 19 chars */
d50f3a
-	        strcpy(myhostad, adhostoverride);
d50f3a
+	if (adhostoverride && strcmp(adhostoverride, notsetstr) != 0) {
d50f3a
+		printerr(1,
d50f3a
+			 "AD host string overridden with \"%s\" from appdefaults\n",
d50f3a
+			 adhostoverride);
d50f3a
+		/* No overflow: Windows cannot handle strings longer than 19 chars */
d50f3a
+		strcpy(myhostad, adhostoverride);
d50f3a
 	} else {
d50f3a
 	        strcpy(myhostad, myhostname);
d50f3a
 	        for (i = 0; myhostad[i] != 0; ++i) {
d50f3a
@@ -928,7 +972,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
d50f3a
 					tried_upper = 1;
d50f3a
 				}
d50f3a
 			} else {
d50f3a
-				printerr(3, "Success getting keytab entry for '%s'\n",spn);
d50f3a
+				printerr(2, "Success getting keytab entry for '%s'\n",spn);
d50f3a
 				retval = 0;
d50f3a
 				goto out;
d50f3a
 			}
d50f3a
@@ -1053,6 +1097,93 @@ err_cache:
d50f3a
 	return (*ret_princname && *ret_realm);
d50f3a
 }
d50f3a
 
d50f3a
+/*
d50f3a
+ * Obtain (or refresh if necessary) Kerberos machine credentials
d50f3a
+ * If a ple is passed in, it's reference will be released
d50f3a
+ */
d50f3a
+static int
d50f3a
+gssd_refresh_krb5_machine_credential_internal(char *hostname,
d50f3a
+				     struct gssd_k5_kt_princ *ple,
d50f3a
+				     char *service, char *srchost)
d50f3a
+{
d50f3a
+	krb5_error_code code = 0;
d50f3a
+	krb5_context context;
d50f3a
+	krb5_keytab kt = NULL;;
d50f3a
+	int retval = 0;
d50f3a
+	char *k5err = NULL;
d50f3a
+	const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
d50f3a
+
d50f3a
+	printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
d50f3a
+		__func__, hostname, ple, service, srchost);
d50f3a
+
d50f3a
+	/*
d50f3a
+	 * If a specific service name was specified, use it.
d50f3a
+	 * Otherwise, use the default list.
d50f3a
+	 */
d50f3a
+	if (service != NULL && strcmp(service, "*") != 0) {
d50f3a
+		svcnames[0] = service;
d50f3a
+		svcnames[1] = NULL;
d50f3a
+	}
d50f3a
+	if (hostname == NULL && ple == NULL)
d50f3a
+		return EINVAL;
d50f3a
+
d50f3a
+	code = krb5_init_context(&context);
d50f3a
+	if (code) {
d50f3a
+		k5err = gssd_k5_err_msg(NULL, code);
d50f3a
+		printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
d50f3a
+			 __func__, k5err);
d50f3a
+		retval = code;
d50f3a
+		goto out;
d50f3a
+	}
d50f3a
+
d50f3a
+	if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
d50f3a
+		k5err = gssd_k5_err_msg(context, code);
d50f3a
+		printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
d50f3a
+			 __func__, k5err, keytabfile);
d50f3a
+		goto out_free_context;
d50f3a
+	}
d50f3a
+
d50f3a
+	if (ple == NULL) {
d50f3a
+		krb5_keytab_entry kte;
d50f3a
+
d50f3a
+		code = find_keytab_entry(context, kt, srchost, hostname,
d50f3a
+					 &kte, svcnames);
d50f3a
+		if (code) {
d50f3a
+			printerr(0, "ERROR: %s: no usable keytab entry found "
d50f3a
+				 "in keytab %s for connection with host %s\n",
d50f3a
+				 __FUNCTION__, keytabfile, hostname);
d50f3a
+			retval = code;
d50f3a
+			goto out_free_kt;
d50f3a
+		}
d50f3a
+
d50f3a
+		ple = get_ple_by_princ(context, kte.principal);
d50f3a
+		k5_free_kt_entry(context, &kte);
d50f3a
+		if (ple == NULL) {
d50f3a
+			char *pname;
d50f3a
+			if ((krb5_unparse_name(context, kte.principal, &pname))) {
d50f3a
+				pname = NULL;
d50f3a
+			}
d50f3a
+			printerr(0, "ERROR: %s: Could not locate or create "
d50f3a
+				 "ple struct for principal %s for connection "
d50f3a
+				 "with host %s\n",
d50f3a
+				 __FUNCTION__, pname ? pname : "<unparsable>",
d50f3a
+				 hostname);
d50f3a
+			if (pname) k5_free_unparsed_name(context, pname);
d50f3a
+			goto out_free_kt;
d50f3a
+		}
d50f3a
+	}
d50f3a
+	retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
d50f3a
+out_free_kt:
d50f3a
+	krb5_kt_close(context, kt);
d50f3a
+out_free_context:
d50f3a
+	if (ple)
d50f3a
+		release_ple(context, ple);
d50f3a
+	krb5_free_context(context);
d50f3a
+out:
d50f3a
+	free(k5err);
d50f3a
+	return retval;
d50f3a
+}
d50f3a
+
d50f3a
 /*==========================*/
d50f3a
 /*===  External routines ===*/
d50f3a
 /*==========================*/
d50f3a
@@ -1146,37 +1277,56 @@ gssd_get_krb5_machine_cred_list(char ***list)
d50f3a
 		goto out;
d50f3a
 	}
d50f3a
 
d50f3a
-	/* Need to serialize list if we ever become multi-threaded! */
d50f3a
-
d50f3a
+	pthread_mutex_lock(&ple_lock);
d50f3a
 	for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
d50f3a
-		if (ple->ccname) {
d50f3a
-			/* Make sure cred is up-to-date before returning it */
d50f3a
-			retval = gssd_refresh_krb5_machine_credential(NULL, ple,
d50f3a
-								      NULL, NULL);
d50f3a
-			if (retval)
d50f3a
-				continue;
d50f3a
-			if (i + 1 > listsize) {
d50f3a
-				listsize += listinc;
d50f3a
-				l = (char **)
d50f3a
-					realloc(l, listsize * sizeof(char *));
d50f3a
-				if (l == NULL) {
d50f3a
-					retval = ENOMEM;
d50f3a
-					goto out;
d50f3a
-				}
d50f3a
-			}
d50f3a
-			if ((l[i++] = strdup(ple->ccname)) == NULL) {
d50f3a
+		if (!ple->ccname)
d50f3a
+			continue;
d50f3a
+
d50f3a
+		/* Take advantage of the fact we only remove the ple
d50f3a
+		 * from the list during shutdown. If it's modified
d50f3a
+		 * concurrently at worst we'll just miss a new entry
d50f3a
+		 * before the current ple
d50f3a
+		 *
d50f3a
+		 * gssd_refresh_krb5_machine_credential_internal() will
d50f3a
+		 * release the ple refcount
d50f3a
+		 */
d50f3a
+		ple->refcount++;
d50f3a
+		pthread_mutex_unlock(&ple_lock);
d50f3a
+		/* Make sure cred is up-to-date before returning it */
d50f3a
+		retval = gssd_refresh_krb5_machine_credential_internal(NULL, ple,
d50f3a
+								       NULL, NULL);
d50f3a
+		pthread_mutex_lock(&ple_lock);
d50f3a
+		if (gssd_k5_kt_princ_list == NULL) {
d50f3a
+			/* Looks like we did shutdown... abort */
d50f3a
+			l[i] = NULL;
d50f3a
+			gssd_free_krb5_machine_cred_list(l);
d50f3a
+			retval = ENOMEM;
d50f3a
+			goto out_lock;
d50f3a
+		}
d50f3a
+		if (retval)
d50f3a
+			continue;
d50f3a
+		if (i + 1 > listsize) {
d50f3a
+			listsize += listinc;
d50f3a
+			l = (char **)
d50f3a
+				realloc(l, listsize * sizeof(char *));
d50f3a
+			if (l == NULL) {
d50f3a
 				retval = ENOMEM;
d50f3a
-				goto out;
d50f3a
+				goto out_lock;
d50f3a
 			}
d50f3a
 		}
d50f3a
+		if ((l[i++] = strdup(ple->ccname)) == NULL) {
d50f3a
+			retval = ENOMEM;
d50f3a
+			goto out_lock;
d50f3a
+		}
d50f3a
 	}
d50f3a
 	if (i > 0) {
d50f3a
 		l[i] = NULL;
d50f3a
 		*list = l;
d50f3a
 		retval = 0;
d50f3a
-		goto out;
d50f3a
 	} else
d50f3a
 		free((void *)l);
d50f3a
+out_lock:
d50f3a
+	pthread_mutex_unlock(&ple_lock);
d50f3a
   out:
d50f3a
 	return retval;
d50f3a
 }
d50f3a
@@ -1201,7 +1351,7 @@ gssd_free_krb5_machine_cred_list(char **list)
d50f3a
  * Called upon exit.  Destroys machine credentials.
d50f3a
  */
d50f3a
 void
d50f3a
-gssd_destroy_krb5_machine_creds(void)
d50f3a
+gssd_destroy_krb5_principals(int destroy_machine_creds)
d50f3a
 {
d50f3a
 	krb5_context context;
d50f3a
 	krb5_error_code code = 0;
d50f3a
@@ -1213,33 +1363,38 @@ gssd_destroy_krb5_machine_creds(void)
d50f3a
 	if (code) {
d50f3a
 		k5err = gssd_k5_err_msg(NULL, code);
d50f3a
 		printerr(0, "ERROR: %s while initializing krb5\n", k5err);
d50f3a
-		goto out;
d50f3a
+		free(k5err);
d50f3a
+		return;
d50f3a
 	}
d50f3a
 
d50f3a
-	for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
d50f3a
-		if (!ple->ccname)
d50f3a
-			continue;
d50f3a
-		if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
d50f3a
-			k5err = gssd_k5_err_msg(context, code);
d50f3a
-			printerr(0, "WARNING: %s while resolving credential "
d50f3a
-				    "cache '%s' for destruction\n", k5err,
d50f3a
-				    ple->ccname);
d50f3a
-			krb5_free_string(context, k5err);
d50f3a
-			k5err = NULL;
d50f3a
-			continue;
d50f3a
-		}
d50f3a
+	pthread_mutex_lock(&ple_lock);
d50f3a
+	while (gssd_k5_kt_princ_list) {
d50f3a
+		ple = gssd_k5_kt_princ_list;
d50f3a
+		gssd_k5_kt_princ_list = ple->next;
d50f3a
 
d50f3a
-		if ((code = krb5_cc_destroy(context, ccache))) {
d50f3a
-			k5err = gssd_k5_err_msg(context, code);
d50f3a
-			printerr(0, "WARNING: %s while destroying credential "
d50f3a
-				    "cache '%s'\n", k5err, ple->ccname);
d50f3a
-			krb5_free_string(context, k5err);
d50f3a
-			k5err = NULL;
d50f3a
+		if (destroy_machine_creds && ple->ccname) {
d50f3a
+			if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
d50f3a
+				k5err = gssd_k5_err_msg(context, code);
d50f3a
+				printerr(0, "WARNING: %s while resolving credential "
d50f3a
+					    "cache '%s' for destruction\n", k5err,
d50f3a
+					    ple->ccname);
d50f3a
+				free(k5err);
d50f3a
+				k5err = NULL;
d50f3a
+			}
d50f3a
+
d50f3a
+			if (!code && (code = krb5_cc_destroy(context, ccache))) {
d50f3a
+				k5err = gssd_k5_err_msg(context, code);
d50f3a
+				printerr(0, "WARNING: %s while destroying credential "
d50f3a
+					    "cache '%s'\n", k5err, ple->ccname);
d50f3a
+				free(k5err);
d50f3a
+				k5err = NULL;
d50f3a
+			}
d50f3a
 		}
d50f3a
+
d50f3a
+		release_ple(context, ple);
d50f3a
 	}
d50f3a
+	pthread_mutex_unlock(&ple_lock);
d50f3a
 	krb5_free_context(context);
d50f3a
-  out:
d50f3a
-	krb5_free_string(context, k5err);
d50f3a
 }
d50f3a
 
d50f3a
 /*
d50f3a
@@ -1247,83 +1402,10 @@ gssd_destroy_krb5_machine_creds(void)
d50f3a
  */
d50f3a
 int
d50f3a
 gssd_refresh_krb5_machine_credential(char *hostname,
d50f3a
-				     struct gssd_k5_kt_princ *ple, 
d50f3a
 				     char *service, char *srchost)
d50f3a
 {
d50f3a
-	krb5_error_code code = 0;
d50f3a
-	krb5_context context;
d50f3a
-	krb5_keytab kt = NULL;;
d50f3a
-	int retval = 0;
d50f3a
-	char *k5err = NULL;
d50f3a
-	const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
d50f3a
-
d50f3a
-	printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
d50f3a
-		__func__, hostname, ple, service, srchost);
d50f3a
-
d50f3a
-	/*
d50f3a
-	 * If a specific service name was specified, use it.
d50f3a
-	 * Otherwise, use the default list.
d50f3a
-	 */
d50f3a
-	if (service != NULL && strcmp(service, "*") != 0) {
d50f3a
-		svcnames[0] = service;
d50f3a
-		svcnames[1] = NULL;
d50f3a
-	}
d50f3a
-	if (hostname == NULL && ple == NULL)
d50f3a
-		return EINVAL;
d50f3a
-
d50f3a
-	code = krb5_init_context(&context);
d50f3a
-	if (code) {
d50f3a
-		k5err = gssd_k5_err_msg(NULL, code);
d50f3a
-		printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
d50f3a
-			 __func__, k5err);
d50f3a
-		retval = code;
d50f3a
-		goto out;
d50f3a
-	}
d50f3a
-
d50f3a
-	if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
d50f3a
-		k5err = gssd_k5_err_msg(context, code);
d50f3a
-		printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
d50f3a
-			 __func__, k5err, keytabfile);
d50f3a
-		goto out_free_context;
d50f3a
-	}
d50f3a
-
d50f3a
-	if (ple == NULL) {
d50f3a
-		krb5_keytab_entry kte;
d50f3a
-
d50f3a
-		code = find_keytab_entry(context, kt, srchost, hostname,
d50f3a
-					 &kte, svcnames);
d50f3a
-		if (code) {
d50f3a
-			printerr(0, "ERROR: %s: no usable keytab entry found "
d50f3a
-				 "in keytab %s for connection with host %s\n",
d50f3a
-				 __FUNCTION__, keytabfile, hostname);
d50f3a
-			retval = code;
d50f3a
-			goto out_free_kt;
d50f3a
-		}
d50f3a
-
d50f3a
-		ple = get_ple_by_princ(context, kte.principal);
d50f3a
-		k5_free_kt_entry(context, &kte);
d50f3a
-		if (ple == NULL) {
d50f3a
-			char *pname;
d50f3a
-			if ((krb5_unparse_name(context, kte.principal, &pname))) {
d50f3a
-				pname = NULL;
d50f3a
-			}
d50f3a
-			printerr(0, "ERROR: %s: Could not locate or create "
d50f3a
-				 "ple struct for principal %s for connection "
d50f3a
-				 "with host %s\n",
d50f3a
-				 __FUNCTION__, pname ? pname : "<unparsable>",
d50f3a
-				 hostname);
d50f3a
-			if (pname) k5_free_unparsed_name(context, pname);
d50f3a
-			goto out_free_kt;
d50f3a
-		}
d50f3a
-	}
d50f3a
-	retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
d50f3a
-out_free_kt:
d50f3a
-	krb5_kt_close(context, kt);
d50f3a
-out_free_context:
d50f3a
-	krb5_free_context(context);
d50f3a
-out:
d50f3a
-	krb5_free_string(context, k5err);
d50f3a
-	return retval;
d50f3a
+    return gssd_refresh_krb5_machine_credential_internal(hostname, NULL,
d50f3a
+							 service, srchost);
d50f3a
 }
d50f3a
 
d50f3a
 /*
d50f3a
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
d50f3a
index b000b444..2415205a 100644
d50f3a
--- a/utils/gssd/krb5_util.h
d50f3a
+++ b/utils/gssd/krb5_util.h
d50f3a
@@ -9,27 +9,13 @@
d50f3a
 #include "gss_oids.h"
d50f3a
 #endif
d50f3a
 
d50f3a
-/*
d50f3a
- * List of principals from our keytab that we
d50f3a
- * will try to use to obtain credentials
d50f3a
- * (known as a principal list entry (ple))
d50f3a
- */
d50f3a
-struct gssd_k5_kt_princ {
d50f3a
-	struct gssd_k5_kt_princ *next;
d50f3a
-	krb5_principal princ;
d50f3a
-	char *ccname;
d50f3a
-	char *realm;
d50f3a
-	krb5_timestamp endtime;
d50f3a
-};
d50f3a
-
d50f3a
 
d50f3a
 int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername,
d50f3a
 				     char *dirname);
d50f3a
 int  gssd_get_krb5_machine_cred_list(char ***list);
d50f3a
 void gssd_free_krb5_machine_cred_list(char **list);
d50f3a
-void gssd_destroy_krb5_machine_creds(void);
d50f3a
+void gssd_destroy_krb5_principals(int destroy_machine_creds);
d50f3a
 int  gssd_refresh_krb5_machine_credential(char *hostname,
d50f3a
-					  struct gssd_k5_kt_princ *ple, 
d50f3a
 					  char *service, char *srchost);
d50f3a
 char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
d50f3a
 void gssd_k5_get_default_realm(char **def_realm);