diff --git a/configure.ac b/configure.ac
index df29cb58a9e0196de16f8803450b3f22d60b1630..fe85a201a918cc1d337dc1f6fd54849784417d0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,7 +80,7 @@ dnl Checks for header files.
 dnl
 AC_CHECK_HEADERS(popt.h mcheck.h values.h socket.h sys/socket.h  \
                  stdbool.h sys/ipc.h sys/shm.h sys/sem.h errno.h \
-                 stdlib.h \
+                 stdlib.h dirent.h \
 		 )
 AC_HEADER_SYS_WAIT
 AC_HEADER_TIME
@@ -484,6 +484,8 @@ AC_CONFIG_FILES([Makefile
 		 src/scancel/Makefile
 		 src/squeue/Makefile
 		 src/sinfo/Makefile
+		 src/plugins/Makefile
+		 src/plugins/auth/Makefile
 		 doc/Makefile
 		 doc/man/Makefile
 		 testsuite/Makefile
diff --git a/etc/slurm.conf.example b/etc/slurm.conf.example
index 63854f470a5ab8a7897edf4ee49008560b7c94b9..84b467f9dff293c7935a55ad609b0a1af62f4538 100644
--- a/etc/slurm.conf.example
+++ b/etc/slurm.conf.example
@@ -127,6 +127,21 @@
 # SlurmctldPidFile=/var/slurm/slurmctld.pid  # default: "/var/run/slurmctld.pid"
 # SlurmdPidFile=/var/slurm/slurmctld.pid     # default: "/var/run/slurmd.pid"
 
+#
+# o Define the authentication method for communicating between SLURM
+#   components
+#
+# "auth/none" : no authentication, the default
+# "auth/authd" : Brett Chun's authd
+#
+# AuthType=auth/none
+
+#
+# o Define the places to look for SLURM plugins.  This is a
+#   colon-separated list of directories, just like the PATH
+#   environment variable.
+#
+# PluginDir=/usr/local/lib # default
 
 #
 # o Define some timeout values for the slurm controller and backup
diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in
index d5b54b84509cfc8f56e2d728516b0212bbd51d0b..fc88900e702af22e5a02bf1295d28ebe80f3bd37 100644
--- a/slurm/slurm.h.in
+++ b/slurm/slurm.h.in
@@ -388,6 +388,8 @@ typedef struct slurm_ctl_conf {
 	char *slurm_conf;	/* pathname of slurm config file */
 	char *state_save_location;/* pathname of slurmctld state save
 				 * directory */
+	char *plugindir;	/* pathname to plugins */
+	char *authtype;		/* authentication type */
 	char *tmp_fs;		/* pathname of temporary file system */
 	char *job_credential_private_key;	/* path to private key */
 	char *job_credential_public_certificate;/* path to public certificate*/
diff --git a/src/Makefile.am b/src/Makefile.am
index 7076d4a12fb4596da541cc1d5be6c20c87c44442..0bd080ce9bac76ce0f97801cc21df45a5024a49a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,9 +1,9 @@
 # $Id$
 
 if USE_INCLUDED_POPT
-SUBDIRS = popt common api slurmctld slurmd srun scontrol scancel squeue sinfo
+SUBDIRS = popt common api slurmctld slurmd srun scontrol scancel squeue sinfo plugins
 else
-SUBDIRS = common api slurmctld slurmd srun scontrol scancel squeue sinfo
+SUBDIRS = common api slurmctld slurmd srun scontrol scancel squeue sinfo plugins
 endif
 
 # make sure popt gets distributed:
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 1b5427a2a813fc1e8eaeef04877f0e8fb3f57416..cf87fcbe9ae4297ffc95ef084f4d2ace4b66d36f 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -11,12 +11,6 @@ else
 elan_sources = 
 endif
 
-if WITH_AUTHD
-auth_sources = slurm_auth_authd.c
-else
-auth_sources = slurm_auth_authd.c
-endif
-
 noinst_LTLIBRARIES = 	\
 	libcommon.la 	\
 	libdaemonize.la \
@@ -40,10 +34,11 @@ libcommon_la_SOURCES = 			\
 	pack.c pack.h			\
 	parse_spec.c parse_spec.h	\
 	plugin.c plugin.h		\
+	plugrack.c plugrack.h		\
 	read_config.c read_config.h	\
 	slurm_errno.c			\
 	slurm_protocol_api.c		\
- 	slurm_protocol_api.h		\
+	slurm_protocol_api.h		\
 	slurm_protocol_pack.c		\
 	slurm_protocol_pack.h		\
 	slurm_protocol_util.c		\
@@ -55,10 +50,9 @@ libcommon_la_SOURCES = 			\
 	slurm_protocol_defs.c		\
 	slurm_protocol_defs.h		\
 	util-net.c util-net.h		\
-	slurm_auth.h			\
+	slurm_auth.c slurm_auth.h	\
 	macros.h			\
-	$(elan_sources) \
-        $(auth_sources)
+	$(elan_sources) 
 
 libdaemonize_la_SOURCES =  \
 	daemonize.c        \
@@ -80,6 +74,6 @@ libeio_la_SOURCES = 	   \
 EXTRA_libcommon_la_SOURCES = \
 	qsw.c qsw.h
 
-libcommon_la_LIBADD   = $(AUTHD_LIBS) $(SSL_LIBS)
+libcommon_la_LIBADD   = $(SSL_LIBS)
 libcred_la_LIBADD     = $(SSL_LIBS) 
 libcred_la_LDFLAGS    = $(SSL_LDFLAGS)	
diff --git a/src/common/plugin.c b/src/common/plugin.c
index c0f49efcf023f422cb56d06369d3452fae3b0da5..5f959d1ece7c9a197d134be4d771c4798dd8557e 100644
--- a/src/common/plugin.c
+++ b/src/common/plugin.c
@@ -24,10 +24,13 @@
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 \*****************************************************************************/
 
+#if HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
 #include <sys/types.h>
 #include <stdio.h>
-#include <assert.h>
-#include <dlfcn.h>
+#include <dlfcn.h>	/* don't know if there's an autoconf for this. */
 
 #include "src/common/plugin.h"
 
@@ -38,52 +41,69 @@ plugin_load_from_file( const char *fq_path )
 	plugin_handle_t plug;
 
 	/* Try to open the shared object. */
-	plug = dlopen( fq_path, RTLD_LAZY );
+	plug = dlopen( fq_path, RTLD_NOW );
 	if ( plug == NULL ) {
-		return NULL;
+		return PLUGIN_INVALID_HANDLE;
 	}
 
 	/* Now see if our required symbols are defined. */
 	if ( ( dlsym( plug, PLUGIN_NAME ) == NULL ) ||
 	     ( dlsym( plug, PLUGIN_TYPE ) == NULL ) ||
 	     ( dlsym( plug, PLUGIN_VERSION ) == NULL ) ) {
-		return NULL;
+		return PLUGIN_INVALID_HANDLE;
 	}
 
 	return plug;
 }
 
 
+/*
+ * Must test plugin validity before doing dlopen() and dlsym()
+ * operations because some implementations of these functions
+ * crash if the library handle is not valid.
+ */
+
 void
 plugin_unload( plugin_handle_t plug )
 {
-	assert( plug );
-	(void) dlclose( plug );
+	if ( plug != PLUGIN_INVALID_HANDLE ) (void) dlclose( plug );
 }
 
 
 void *
 plugin_get_sym( plugin_handle_t plug, const char *name )
 {
-	return dlsym( plug, name );
+	if ( plug != PLUGIN_INVALID_HANDLE )
+		return dlsym( plug, name );
+	else
+		return NULL;
 }
 
 const char *
 plugin_get_name( plugin_handle_t plug )
 {
-	return (const char *) dlsym( plug, PLUGIN_NAME );
+	if ( plug != PLUGIN_INVALID_HANDLE )
+		return (const char *) dlsym( plug, PLUGIN_NAME );
+	else
+		return NULL;
 }
 
 const char *
 plugin_get_type( plugin_handle_t plug )
 {
-	return (const char *) dlsym( plug, PLUGIN_TYPE );
+	if ( plug != PLUGIN_INVALID_HANDLE )
+		return (const char *) dlsym( plug, PLUGIN_TYPE );
+	else
+		return NULL;
 }
 
 uint32_t
 plugin_get_version( plugin_handle_t plug )
 {
-	uint32_t *ptr = (uint32_t *) dlsym( plug, PLUGIN_VERSION );
+	uint32_t *ptr;
+
+	if ( plug == PLUGIN_INVALID_HANDLE ) return 0;	
+	ptr = (uint32_t *) dlsym( plug, PLUGIN_VERSION );
 	return ptr ? *ptr : 0;
 }
 
diff --git a/src/common/plugrack.c b/src/common/plugrack.c
new file mode 100644
index 0000000000000000000000000000000000000000..d8461db382f33dad48a15827c8f917533a4428dc
--- /dev/null
+++ b/src/common/plugrack.c
@@ -0,0 +1,588 @@
+/*****************************************************************************\
+ * plugrack.c - an intelligent container for plugins
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by AUTHOR <AUTHOR@llnl.gov>.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#if HAVE_CONFIG_H
+#  include "config.h"
+
+#  if HAVE_DIRENT_H
+#    include <dirent.h>
+#    define NAMLEN(dirent) strlen((dirent)->d_name)
+#  else /* ! HAVE_DIRENT_H */
+#    define dirent direct
+#    define NAMLEN(dirent) (dirent)->d_namlen
+#  endif /* HAVE_DIRENT_H */
+
+#  if STDC_HEADERS
+#    include <string.h>
+#    include <stdlib.h>
+#  else /* ! STDC_HEADERS */
+#    if !HAVE_STRCHR
+#      define strchr index
+#      define strrchr rindex
+       char *strchr(), *strrchr();
+#    endif /* HAVE_STRCHR */
+#  endif /* STDC_HEADERS */
+
+#  if HAVE_UNISTD_H
+#    include <unistd.h>
+#  endif /* HAVE_UNISTD_H */
+#  if HAVE_SYS_TYPES_H
+#    include <sys/types.h>
+#  endif
+#  if HAVE_SYS_STAT_H
+#    include <sys/stat.h>
+#  endif
+
+#else /* ! HAVE_CONFIG_H */
+#  include <dirent.h>
+#  include <string.h>
+#  include <stdlib.h>
+#  include <unistd.h>
+#  include <dirent.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "src/common/xassert.h"
+#include "src/common/xmalloc.h"
+#include "src/common/xstring.h"
+#include "src/common/plugrack.h"
+
+/*
+ * Represents a plugin in the rack.
+ *
+ * full_type is the fully-qualified plugin type, e.g., "auth/kerberos".
+ * For the low-level plugin interface the type can be whatever it needs
+ * to be.  For the rack-level interface, the type exported by the plugin
+ * must be of the form "<major>/<minor>".
+ *
+ * fq_path is the fully-qualified pathname to the plugin.
+ *
+ * plug is the plugin handle.  If it is equal to PLUGIN_INVALID_HANDLE
+ * then the plugin is not currently loaded in memory.
+ *
+ * refcount shows how many clients have requested to use the plugin.
+ * If this is zero, the rack code may decide to unload the plugin.
+ */
+typedef struct _plugrack_entry {
+	const char *full_type;
+	const char *fq_path;
+	plugin_handle_t	plug;
+	int refcount;
+} plugrack_entry_t;
+
+/*
+ * Implementation of the plugin rack.
+ *
+ * entries is the list of plugrack_entry_t.
+ *
+ * uid is the Linux UID of the person authorized to own the plugin
+ * and write to the plugin file and the directory where it is stored.
+ * This field is used only if paranoia is nonzero.
+ *
+ * paranoia is a set of bit flags indicating what operations should be
+ * done to verify the integrity and authority of the plugin before
+ * loading it.
+ */
+struct _plugrack {
+	List entries;
+	const char *major_type;
+	uid_t uid;
+	uint8_t	paranoia;
+};
+
+#define PLUGRACK_UID_NOBODY		99	/* RedHat's, anyway. */
+
+/*
+ * Destructor function for the List code.  This should entirely
+ * clean up a plugin_entry_t.
+ */
+static void
+plugrack_entry_destructor( void *v )
+{
+	plugrack_entry_t *victim = v;
+  
+	if ( victim == NULL ) return;
+
+	/*
+	 * Free memory and unload the plugin if necessary.  The assert
+	 * is to make sure we were actually called from the List destructor
+	 * which should only be callable from plugrack_destroy().
+	 */
+	xassert( victim->refcount == 0 );
+	if ( victim->full_type ) xfree( victim->full_type );
+	if ( victim->fq_path ) xfree( victim->fq_path );
+	if ( victim->plug != PLUGIN_INVALID_HANDLE ) plugin_unload( victim->plug );
+	xfree( victim );
+}
+
+/*
+ * Check a pathname to see if it is owned and writable by the appropriate
+ * users, and writable by no one else.  The path can be either to a file
+ * or to a directory.  This is so, when fishing for plugins in a whole
+ * directory, we can test the directory once and then each file.
+ *
+ * Returns non-zero if the file system node indicated by the path name
+ * is owned by the user in the plugin rack and not writable by anyone
+ * else, and these actions are requested by the rack's paranoia policy.
+ */
+static int
+accept_path_paranoia( plugrack_t rack,
+		      const char *fq_path,
+		      int check_own,
+		      int check_write )
+{
+	struct stat st;
+
+	/* Internal function, so assert rather than fail gracefully. */
+	xassert( rack );
+	xassert( fq_path );
+  
+	if ( stat( fq_path, &st ) < 0 ) {
+		return 0;
+	}
+  
+	/* Is path owned by authorized user? */
+	if ( check_own ) {
+		if ( st.st_uid != rack->uid ) return 0;
+	}
+
+	/* Is path writable by others? */
+	if ( check_write ) {
+		if ( ( st.st_mode & S_IWGRP ) || ( st.st_mode & S_IWOTH ) ) return 0;
+	}
+
+	return 1;
+}
+
+
+/*
+ * Check a file to see if its permissions and location are appropriate
+ * for a plugin.  This checks both a file and its parent directory for
+ * correct ownership and writability.
+ *
+ * The permissions and ownerships to check are given in the paranoia
+ * policy of the plugin rack.
+ *
+ * Returns nonzero if the plugin is acceptable.
+ */
+static int
+accept_paranoia( plugrack_t rack, const char *fq_path )
+{
+	char *local;
+	char *p;
+  
+	xassert( rack );
+	xassert( fq_path );
+
+	/* Trivial accept. */
+	if ( ! rack->paranoia ) return 1;
+  
+	/* Make a local copy of the path name so we can write into it. */
+	local = alloca( strlen( fq_path ) + 1 );
+	strcpy( local, fq_path );
+
+	if ( ! accept_path_paranoia( rack,
+								 local,
+								 rack->paranoia & PLUGRACK_PARANOIA_FILE_OWN,
+								 rack->paranoia & PLUGRACK_PARANOIA_FILE_WRITABLE ) ) {
+		return 0;
+	}
+
+	/*
+	 * Find the directory name by chopping off the last path element.
+	 * This also helps weed out malformed file names.  We specify that
+	 * plugins be specified by fully-qualified pathnames and that means
+	 * it should have at least one delimiter.
+	 */
+	if ( ( p = strrchr( local, '/' ) ) == NULL ) {
+		return 0;
+	}
+	if ( p != local ) *p = 0;
+
+	return accept_path_paranoia( rack,
+								 local,
+								 rack->paranoia & PLUGRACK_PARANOIA_DIR_OWN,
+								 rack->paranoia & PLUGRACK_PARANOIA_DIR_WRITABLE );
+}
+
+/*
+ * Load a plugin.  Check its type, but not any of the onwership or
+ * writability.  It is presumed that those have already been checked.
+ */
+static plugin_handle_t
+plugrack_open_plugin( plugrack_t rack, const char *fq_path )
+{
+	plugin_handle_t plug;
+
+	if ( ! rack ) return PLUGIN_INVALID_HANDLE;
+	if ( ! fq_path ) return PLUGIN_INVALID_HANDLE;
+  
+	/* See if we can actually load the plugin. */
+	plug = plugin_load_from_file( fq_path );
+	if ( plug == PLUGIN_INVALID_HANDLE ) return PLUGIN_INVALID_HANDLE;
+
+	/* Now see if this is the right type. */
+	if ( rack->major_type &&
+		 ( strncmp( rack->major_type,
+					plugin_get_type( plug ),
+					strlen( rack->major_type ) ) != 0 ) ) {
+		plugin_unload( plug );
+		return PLUGIN_INVALID_HANDLE;
+	}
+
+	return plug;
+}
+
+
+plugrack_t plugrack_create( void )
+{
+	plugrack_t rack = (plugrack_t) xmalloc( sizeof( struct _plugrack ) );
+
+	rack->paranoia     = PLUGRACK_PARANOIA_NONE;
+	rack->major_type   = NULL;
+	rack->uid          = PLUGRACK_UID_NOBODY;
+	rack->entries      = list_create( plugrack_entry_destructor );
+	if ( rack->entries == NULL ) {
+		xfree( rack );
+		return NULL;
+	}
+	return rack;
+}
+
+
+int
+plugrack_destroy( plugrack_t rack )
+{
+	ListIterator it;
+	plugrack_entry_t *e;
+  
+	if ( ! rack ) return SLURM_ERROR;
+
+	/*
+	 * See if there are any plugins still being used.  If we unload them,
+	 * the program might crash because cached virtual mapped addresses
+	 * will suddenly be outside our virtual address space.
+	 */
+	it = list_iterator_create( rack->entries );
+	while ( ( e = list_next( it ) ) != NULL ) {
+		if ( e->refcount > 0 ) {
+			list_iterator_destroy( it );
+			return SLURM_ERROR; /* plugins still in use. */
+		}
+	}
+	list_iterator_destroy( it );
+
+	list_destroy( rack->entries );
+	xfree( rack );
+	return SLURM_SUCCESS;
+}
+
+
+int
+plugrack_set_major_type( plugrack_t rack, const char *type )
+{
+	if ( ! rack ) return SLURM_ERROR;
+	if ( ! type ) return SLURM_ERROR;
+
+	/* Free any pre-existing type. */
+	if ( rack->major_type ) xfree( rack->major_type );
+	rack->major_type = NULL;
+
+	/* Install a new one. */
+	if ( type != NULL ) {
+		rack->major_type = xstrdup( type );
+		if ( rack->major_type == NULL ) return SLURM_ERROR;
+	}
+  
+	return SLURM_SUCCESS;
+}
+
+
+int
+plugrack_set_paranoia( plugrack_t rack,
+		       const uint32_t flags,
+		       const uid_t uid )
+
+{
+	if ( ! rack ) return SLURM_ERROR;
+
+	rack->paranoia = flags;
+	if ( flags ) {
+		rack->uid = uid;
+	}
+
+	return SLURM_SUCCESS;
+}
+
+int
+plugrack_add_opened_plugin( plugrack_t rack,
+							plugin_handle_t *plug,
+							const char *fq_path )
+{
+	plugrack_entry_t *e;
+  
+	if ( ! rack ) return SLURM_ERROR;
+	if ( ! plug ) return SLURM_ERROR;
+	if ( ! fq_path ) return SLURM_ERROR;
+
+	e = (plugrack_entry_t *) xmalloc( sizeof( plugrack_entry_t ) );
+
+	e->full_type = xstrdup( plugin_get_type( plug ) );
+	e->fq_path	= xstrdup( fq_path );
+	e->plug	= plug;
+	e->refcount	= 0;
+  
+	list_append( rack->entries, e );
+
+	return SLURM_SUCCESS;
+}
+
+  
+int
+plugrack_add_plugin_file( plugrack_t rack, const char *fq_path )
+{
+	plugin_handle_t plug;
+
+	if ( ! rack ) return SLURM_ERROR;
+	if ( ! fq_path ) return SLURM_ERROR;
+
+	/*
+	 * See if we should open this plugin.  Paranoia checks must
+	 * always be done first since code can be executed in the plugin
+	 * simply by opening it.
+	 */
+	if ( ! accept_paranoia( rack, fq_path ) ) return SLURM_ERROR;
+
+	/* Try to open plugin, testing the type. */
+	plug = plugrack_open_plugin( rack, fq_path );
+	if ( plug == PLUGIN_INVALID_HANDLE ) return SLURM_ERROR;
+
+	/* Add it to the list. */
+	return plugrack_add_opened_plugin( rack, plug, fq_path );
+}
+
+
+
+int
+plugrack_read_dir( plugrack_t rack,
+		   const char *dir )
+{
+	char *fq_path;
+	char *tail;
+	DIR *dirp;
+	struct dirent *e;
+	struct stat st;
+	plugin_handle_t plug;
+
+	if ( ! rack ) return SLURM_ERROR;
+	if ( ! dir ) return SLURM_ERROR;
+  
+	/* Allocate a buffer for fully-qualified path names. */
+	fq_path = alloca( strlen( dir ) + NAME_MAX + 1 );
+	xassert( fq_path );
+
+	/*
+	 * Write the directory name in it, then a separator, then
+	 * keep track of where we want to write the individual file
+	 * names.
+	 */
+	strcpy( fq_path, dir );
+	tail = &fq_path[ strlen( dir ) ];
+	*tail = '/';
+	++tail;
+
+	/* Check whether we should be paranoid about this directory. */
+	if ( ! accept_path_paranoia( rack,
+								 dir,
+								 rack->paranoia & PLUGRACK_PARANOIA_DIR_OWN,
+								 rack->paranoia & PLUGRACK_PARANOIA_DIR_WRITABLE ) ) {
+		return SLURM_ERROR;
+	}
+  
+	/* Open the directory. */
+	dirp = opendir( dir );
+	if ( dirp == NULL ) return SLURM_ERROR;
+  
+	while ( 1 ) {
+		e = readdir( dirp );
+		if ( e == NULL ) break;
+
+		/*
+		 * Compose file name.  Where NAME_MAX is defined it represents the
+		 * largest file name given in a dirent.  This macro is used in the
+		 * allocation of "tail" above, so this unbounded copy should work.
+		 */
+		strcpy( tail, e->d_name );
+
+		/* Check only regular files. */
+		if ( stat( fq_path, &st ) < 0 ) continue;
+		if ( ! S_ISREG( st.st_mode ) ) continue;
+
+		/* See if we should be paranoid about this file. */
+		if ( ! accept_path_paranoia( rack,
+									 dir,
+									 rack->paranoia & PLUGRACK_PARANOIA_FILE_OWN,
+									 rack->paranoia & PLUGRACK_PARANOIA_FILE_WRITABLE ) ) {
+			continue;
+		}
+
+		/* Load the plugin. */
+		plug = plugrack_open_plugin( rack, fq_path );
+		if ( plug == PLUGIN_INVALID_HANDLE ) {
+			continue;
+		}
+    
+		/* Add it to the list. */
+		(void) plugrack_add_opened_plugin( rack, plug, fq_path );    
+	}
+
+	return SLURM_SUCCESS;
+}
+
+int
+plugrack_read_cache( plugrack_t rack,
+		     const char *cache_file )
+{
+	/* Don't care for now. */
+  
+	return SLURM_ERROR;
+}
+
+
+int
+plugrack_purge_idle( plugrack_t rack )
+{
+	ListIterator it;
+	plugrack_entry_t *e;
+  
+	if ( ! rack ) return SLURM_ERROR;
+
+	it = list_iterator_create( rack->entries );
+	while ( ( e = list_next( it ) ) != NULL ) {
+		if ( ( e->plug != PLUGIN_INVALID_HANDLE ) &&
+			 ( e->refcount == 0 ) ){
+			plugin_unload( e->plug );
+			e->plug = PLUGIN_INVALID_HANDLE;
+		}
+	}
+
+	list_iterator_destroy( it );
+	return SLURM_SUCCESS;
+}
+
+
+int
+plugrack_load_all( plugrack_t rack )
+{
+	ListIterator it;
+	plugrack_entry_t *e;
+
+	if ( ! rack ) return SLURM_ERROR;
+
+	it = list_iterator_create( rack->entries );
+	while ( ( e = list_next( it ) ) != NULL ) {
+		if ( e->plug == PLUGIN_INVALID_HANDLE ) {
+			(void) plugin_load_from_file( e->fq_path );
+		}
+	}
+
+	list_iterator_destroy( it );
+	return SLURM_SUCCESS;
+}
+
+
+int
+plugrack_write_cache( plugrack_t rack,
+		      const char *cache )
+{
+	/* Not implemented. */
+  
+	return SLURM_SUCCESS;
+}
+
+plugin_handle_t
+plugrack_use_by_type( plugrack_t rack,
+		      const char *full_type )
+{
+	ListIterator it;
+	plugrack_entry_t *e;
+  
+	if ( ! rack ) return PLUGIN_INVALID_HANDLE;
+	if ( ! full_type ) return PLUGIN_INVALID_HANDLE;
+
+	it = list_iterator_create( rack->entries );
+	while ( ( e = list_next( it ) ) != NULL ) {
+		if ( strcmp( full_type, e->full_type ) != 0 ) continue;
+
+		/* See if plugin is loaded. */
+		if ( e->plug == PLUGIN_INVALID_HANDLE ) {
+			e->plug = plugin_load_from_file( e->fq_path );
+		}
+
+		/* If load was successful, increment the reference count. */
+		if ( e->plug == PLUGIN_INVALID_HANDLE )
+			e->refcount++;
+
+		/*
+		 * Return the plugin, even if it failed to load -- this serves
+		 * as an error return value.
+		 */
+		list_iterator_destroy( it );
+		return e->plug;
+	}
+
+	/* Couldn't find a suitable plugin. */
+	list_iterator_destroy( it );
+	return PLUGIN_INVALID_HANDLE;
+}
+
+
+int
+plugrack_finished_with_plugin( plugrack_t rack, plugin_handle_t plug )
+{
+	ListIterator it;
+	plugrack_entry_t *e;
+
+	if ( ! rack ) return SLURM_ERROR;
+
+	it = list_iterator_create( rack->entries );
+	while ( ( e = list_next( it ) ) != NULL ) {
+		if ( e->plug == plug ) {
+			e->refcount--;
+			if ( e->refcount < 0 ) e->refcount = 0;
+
+			/* Do something here with purge policy. */
+
+			list_iterator_destroy( it );
+			return SLURM_SUCCESS;
+		}
+	}
+
+	/* Plugin not in this rack. */
+	list_iterator_destroy( it );
+	return SLURM_ERROR;
+}
diff --git a/src/common/plugrack.h b/src/common/plugrack.h
new file mode 100644
index 0000000000000000000000000000000000000000..121444dea06ebdfaa26d6d503faa018899283c75
--- /dev/null
+++ b/src/common/plugrack.h
@@ -0,0 +1,186 @@
+/*****************************************************************************\
+ * plugrack.h - an intelligent container for plugins
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by AUTHOR <AUTHOR@llnl.gov>.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#ifndef __PLUGRACK_H__
+#define __PLUGRACK_H__
+
+#include "src/common/plugin.h"
+#include "src/common/list.h"
+
+/* Opaque type for plugin rack. */
+typedef struct _plugrack * plugrack_t;
+
+/*
+ * Returns a new plugin rack object on success and NULL on failure.
+ */
+plugrack_t plugrack_create( void );
+
+/*
+ * Destroy a plugin rack.  All the associated plugins are unloaded and
+ * all associated memory is deallocated.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_destroy( plugrack_t rack );
+
+/*
+ * Set the major type of the plugins for this rack.  This affects
+ * subsequent calls to add plugins from files.
+ *
+ * Pass NULL to disable typing in plugins handled by this rack.
+ * This is the default.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_set_major_type( plugrack_t rack, const char *type );
+
+/*
+ * Paranoia settings.  OR these together, if desired.
+ *
+ * _DIR_OWN - verify that the directory containing the plugin is owned
+ * by a certain user.
+ * _DIR_WRITABLE - verify that the directory containing the plugin is
+ * not writable by anyone except its owner.
+ * _FILE_OWN - verify that the plugin is owned by a certain user.
+ * _FILE_WRITABLE - verify that the plugin is not writable by anyone
+ * except its onwer.
+ */
+#define PLUGRACK_PARANOIA_NONE			0x00
+#define PLUGRACK_PARANOIA_DIR_OWN		0x01
+#define PLUGRACK_PARANOIA_DIR_WRITABLE		0x02
+#define PLUGRACK_PARANOIA_FILE_OWN		0x04
+#define PLUGRACK_PARANOIA_FILE_WRITABLE		0x08
+
+/*
+ * Indicate the manner in which the rack should be paranoid about
+ * accepting plugins.
+ *
+ * paranoia_flags is an ORed combination of the flags listed above.
+ * They do not combine across separate calls; the flags must be fully
+ * specified at each call.
+ *
+ * The paranoia setting affects only subsequent attempts to place
+ * plugins in the rack.
+ *
+ * If the flag parameter specifies ownership checking, "uid" gives the
+ * numerical user ID of the authorized owner of the plugin and the
+ * directory where it resides.  If no ownership checking is requested,
+ * this parameter is ignored.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_set_paranoia( plugrack_t rack,
+			   const uint32_t paranoia_flags,
+			   const uid_t uid );
+
+/*
+ * Add a plugin to a rack by giving the pathname to the plugin.
+ *
+ * If a type has been set for this rack, the plugin's major type must
+ * match or an error results.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_add_plugin_file( plugrack_t rack, const char *fq_path );
+
+/*
+ * Add plugins to a rack by scanning the given directory.  If a
+ * type has been set for this rack, only those plugins whose major type
+ * matches the rack's type will be loaded.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_read_dir( plugrack_t rack,
+		       const char *dir );
+
+/*
+ * Identical to plugrack_read_dir() except that additional criteria are
+ * tested:
+ *
+ * 1. The directory must be owned by the specified UID and must be
+ * writable by that user only; "other" and "group" may not write to
+ * it.
+ *
+ * 2. Each candidate plugin must be owned by the specified UID and
+ * must not be writable by any other means.  In addition, the plugin's
+ * setuid bit must be cleared.
+ */
+int plugrack_read_dir_paranoid( plugrack_t rack,
+				const char *dir,
+				uid_t uid );
+
+/*
+ * Add plugins to the rack by reading the given cache.  Note that plugins
+ * may not actually load, but the rack will be made aware of them.
+ *
+ * NOT CURRENTLY IMPLEMENTED.
+ */
+int plugrack_read_cache( plugrack_t rack,
+			 const char *cache );
+
+/*
+ * Remove from memory all plugins that are not currently in use by the
+ * program.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_unload_idle( plugrack_t rack );
+
+/*
+ * Load into memory all plugins which are currently unloaded.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_load_all( plugrack_t rack );
+
+/*
+ * Write the current contents of the plugin rack to a file
+ * in cache format, suitable to be read later using plugrack_read_cache().
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_write_cache( plugrack_t rack, const char *cache );
+
+/*
+ * Find a plugin in the rack which matches the given minor type,
+ * load it if necessary, and return a handle to it.
+ *
+ * Returns PLUGIN_INVALID_HANDLE if a suitable plugin cannot be
+ * found or loaded.
+ */
+plugin_handle_t plugrack_use_by_type( plugrack_t rack,
+				      const char *type );
+
+/*
+ * Indicate that a plugin is no longer needed.  Whether the plugin
+ * is actually unloaded depends on the rack's disposal policy.
+ *
+ * Returns a SLURM errno.
+ */
+int plugrack_finished_with_plugin( plugrack_t rack, plugin_handle_t plug );
+
+
+#endif /*__PLUGRACK_H__*/
diff --git a/src/common/read_config.c b/src/common/read_config.c
index fb5e884475e4e5055471dfa4333090a8b99f0bc8..1e6251936853c2cbf8242e87b4e3452634698ce1 100644
--- a/src/common/read_config.c
+++ b/src/common/read_config.c
@@ -128,6 +128,8 @@ init_slurm_conf (slurm_ctl_conf_t *ctl_conf_ptr)
 	xfree (ctl_conf_ptr->slurmd_spooldir);
 	ctl_conf_ptr->slurmd_timeout		= (uint16_t) NO_VAL;
 	xfree (ctl_conf_ptr->state_save_location);
+	xfree (ctl_conf_ptr->plugindir);
+	xfree (ctl_conf_ptr->authtype );
 	xfree (ctl_conf_ptr->tmp_fs);
 	return;
 }
@@ -163,6 +165,7 @@ parse_config_spec (char *in_line, slurm_ctl_conf_t *ctl_conf_ptr)
 	char *slurmctld_logfile = NULL, *slurmctld_port = NULL;
 	char *slurmd_logfile = NULL, *slurmd_port = NULL;
 	char *slurmd_spooldir = NULL, *slurmd_pidfile = NULL;
+	char *plugindir = NULL, *authtype = NULL;
 	char *job_credential_private_key = NULL;
 	char *job_credential_public_certificate = NULL;
 	long first_job_id = -1;
@@ -198,7 +201,9 @@ parse_config_spec (char *in_line, slurm_ctl_conf_t *ctl_conf_ptr)
 		"SlurmdPort=", 's', &slurmd_port,
 		"SlurmdSpoolDir=", 's', &slurmd_spooldir,
 		"SlurmdTimeout=", 'd', &slurmd_timeout,
-		"StateSaveLocation=", 's', &state_save_location, 
+		"StateSaveLocation=", 's', &state_save_location,
+		"PluginDir=", 's', &plugindir,
+		"AuthType=", 's', &authtype,
 		"TmpFS=", 's', &tmp_fs,
 		"END");
 
@@ -417,6 +422,22 @@ parse_config_spec (char *in_line, slurm_ctl_conf_t *ctl_conf_ptr)
 		ctl_conf_ptr->state_save_location = state_save_location;
 	}
 
+	if ( plugindir ) {
+		if ( ctl_conf_ptr->plugindir ) {
+			error( MULTIPLE_VALUE_MSG, "PluginDir" );
+			xfree( ctl_conf_ptr->plugindir );
+		}
+		ctl_conf_ptr->plugindir = plugindir;
+	}
+	
+	if ( authtype ) {
+		if ( ctl_conf_ptr->authtype ) {
+			error( MULTIPLE_VALUE_MSG, "AuthType" );
+			xfree( ctl_conf_ptr->authtype );
+		}
+		ctl_conf_ptr->authtype = authtype;
+	}
+
 	if ( tmp_fs ) {
 		if ( ctl_conf_ptr->tmp_fs ) {
 			error (MULTIPLE_VALUE_MSG, "TmpFS");
diff --git a/src/common/slurm_auth.c b/src/common/slurm_auth.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7b7e864edce8b7720f36abb7013a944b1077842
--- /dev/null
+++ b/src/common/slurm_auth.c
@@ -0,0 +1,476 @@
+/*****************************************************************************\
+ *  slurm_auth.h - implementation-independent authentication API definitions
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Kevin Tew <tew1@llnl.gov> et. al.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <pthread.h>
+
+#include "src/common/macros.h"
+#include "src/common/xmalloc.h"
+#include "src/common/xassert.h"
+#include "src/common/xstring.h"
+#include "src/common/read_config.h"
+#include "src/common/slurm_auth.h"
+#include "src/common/plugin.h"
+#include "src/common/plugrack.h"
+
+/*
+ * WARNING:  Do not change the order of these fields or add additional
+ * fields at the beginning of the structure.  If you do, authentication
+ * plugins will stop working.  If you need to add fields, add them at the
+ * end of the structure.
+ */
+typedef struct slurm_auth_ops {
+	void *	(*alloc)	( void );
+	void	(*free)		( void *cred );
+	int		(*activate)	( void *cred, int secs );
+	int		(*verify)	( void *cred );
+	uid_t	(*get_uid)	( void *cred );
+	gid_t	(*get_gid)	( void *cred );
+	void	(*pack)		( void *cred, Buf buf );
+	int		(*unpack)	( void *cred, Buf buf );
+	void	(*print)	( void *cred, FILE *fp );
+} slurm_auth_ops_t;
+
+/*
+ * Implementation of the authentication context.  Hopefully everything
+ * having to do with plugins will be abstracted under here so that the
+ * callers can just deal with creating a context and asking for the
+ * operations implemented pertinent to that context.
+ *
+ * auth_type - the string (presumably from configuration files)
+ * describing the desired form of authentication, such as "auth/munged"
+ * or "auth/kerberos" or "auth/none".
+ *
+ * plugin_list - the plugin rack managing the loading and unloading of
+ * plugins for authencation.
+ *
+ * cur_plugin - the plugin currently supplying operations to the caller.
+ *
+ * ops - a table of pointers to functions in the plugin which correspond
+ * to the standardized plugin API.  We create this table by text references
+ * into the plugin's symbol table.
+ */
+struct slurm_auth_context {
+	char *auth_type;
+	plugrack_t plugin_list;
+	plugin_handle_t	cur_plugin;
+	slurm_auth_ops_t ops;
+};
+
+/*
+ * A global authentication context.  "Global" in the sense that there's
+ * only one, with static bindings.  We don't export it.
+ */
+static slurm_auth_context_t g_context = NULL;
+
+static slurm_ctl_conf_t conf;
+static pthread_mutex_t config_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static char *
+get_plugin_dir( void )
+{
+	slurm_mutex_lock( &config_lock );
+	if ( conf.slurmd_port == 0 ) {
+		read_slurm_conf_ctl( &conf );
+	}
+	if ( conf.plugindir == NULL ) {
+		conf.plugindir = xstrdup( "/usr/local/lib" );
+	}
+	slurm_mutex_unlock( &config_lock );
+	
+	return conf.plugindir;
+}
+
+static char *
+get_auth_type( void )
+{
+	slurm_mutex_lock( &config_lock );
+	if ( conf.slurmd_port == 0 ) {
+		read_slurm_conf_ctl( &conf );
+	}
+	if ( conf.authtype == NULL ) {
+		conf.authtype = xstrdup( "auth/none" );
+	}
+	slurm_mutex_unlock( &config_lock );
+
+	return conf.authtype;
+}
+
+
+/*
+ * Resolve the operations from the plugin.
+ */
+static slurm_auth_ops_t *
+slurm_auth_get_ops( slurm_auth_context_t c )
+{
+	/*
+	 * These strings must be kept in the same order as the fields
+	 * declared for slurm_auth_ops_t.
+	 */
+	static const char *syms[] = {
+		"slurm_auth_alloc",
+		"slurm_auth_free",
+		"slurm_auth_activate",
+		"slurm_auth_verify",
+		"slurm_auth_get_uid",
+		"slurm_auth_get_gid",
+		"slurm_auth_pack",
+		"slurm_auth_unpack",
+		"slurm_auth_print"
+	};
+	int n_syms = sizeof( syms ) / sizeof( char * );
+
+	/* Get the plugin list, if needed. */
+	if ( c->plugin_list == NULL ) {
+		c->plugin_list = plugrack_create();
+		if ( c->plugin_list == NULL ) {
+			verbose( "Unable to create a plugin manager" );
+			return NULL;
+		}
+
+		plugrack_set_major_type( c->plugin_list, "auth" );
+		plugrack_set_paranoia( c->plugin_list, PLUGRACK_PARANOIA_NONE, 0 );
+		plugrack_read_dir( c->plugin_list, get_plugin_dir() );
+	}
+  
+	/* Find the correct plugin. */
+	c->cur_plugin = plugrack_use_by_type( c->plugin_list, c->auth_type );
+	if ( c->cur_plugin == PLUGIN_INVALID_HANDLE ) {
+		verbose( "can't find a plugin for type %s", c->auth_type );
+		return NULL;
+	}  
+
+	/* Dereference the API. */
+	if ( plugin_get_syms( c->cur_plugin,
+						  n_syms,
+						  syms,
+						  (void **) &c->ops ) < n_syms ) {
+		verbose( "incomplete plugin detected" );
+		return NULL;
+	}
+
+	return &c->ops;
+}
+
+
+slurm_auth_context_t
+slurm_auth_context_create( const char *auth_type )
+{
+	slurm_auth_context_t c;
+  
+	if ( auth_type == NULL ) {
+		debug( "slurm_auth_context_create: no authentication type" );
+		return NULL;
+	}
+
+	c = (slurm_auth_context_t) xmalloc( sizeof( struct slurm_auth_context ) );
+
+	/* Copy the authentication type. */
+	c->auth_type = strdup( auth_type );
+	if ( c->auth_type == NULL ) {
+		debug( "can't make local copy of authentication type" );
+		xfree( c );
+		return NULL;
+	}
+
+	/* Plugin rack is demand-loaded on first reference. */
+	c->plugin_list = NULL;
+
+	c->cur_plugin = PLUGIN_INVALID_HANDLE;  
+
+	return c;
+}
+
+int
+slurm_auth_context_destroy( slurm_auth_context_t c )
+{    
+	/*
+	 * Must check return code here because plugins might still
+	 * be loaded and active.
+	 */
+	if ( c->plugin_list ) {
+		if ( plugrack_destroy( c->plugin_list ) != SLURM_SUCCESS ) {
+			return SLURM_ERROR;
+		}
+	}  
+
+	free( c->auth_type );
+	xfree( c );
+	
+	return SLURM_SUCCESS;
+}
+
+int
+slurm_auth_init( void )
+{
+	if ( g_context ) {
+		return SLURM_SUCCESS;
+	}
+
+	
+	g_context = slurm_auth_context_create( get_auth_type() );
+	if ( g_context == NULL ) {
+		verbose( "cannot create a context for %s", get_auth_type() );
+		return SLURM_ERROR;
+	}
+	
+	if ( slurm_auth_get_ops( g_context ) == NULL ) {
+		verbose( "cannot resolve plugin operations" );
+		return SLURM_ERROR;
+	} else {
+		return SLURM_SUCCESS;
+	}
+}
+
+/*
+ * Static bindings for an arbitrary authentication context.  Heaven
+ * help you if you try to pass credentials from one context to the
+ * functions for a different context.
+ */
+void *
+c_slurm_auth_alloc( slurm_auth_context_t c )
+{
+	if ( c == NULL ) return NULL;
+	if ( c->ops.alloc ) {
+		return (*(c->ops.alloc))();
+	} else {
+		return NULL;
+	}
+}
+
+void
+c_slurm_auth_free( slurm_auth_context_t c, void *cred )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) ) return;
+	if ( c->ops.free ) {
+		(*(c->ops.free))( cred );
+	}
+}
+
+int
+c_slurm_auth_activate( slurm_auth_context_t c, void *cred, int secs )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) ) return SLURM_ERROR;
+	if ( c->ops.activate ) {
+		return (*(c->ops.activate))( cred, secs );
+	} else {
+		return SLURM_ERROR;
+	}
+}
+
+int
+c_slurm_auth_verify( slurm_auth_context_t c, void *cred )
+{	
+	if ( ( c == NULL ) || ( cred == NULL ) ) return SLURM_ERROR;
+	if ( c->ops.verify ) {
+		return (*(c->ops.verify))( cred );
+	} else {
+		return SLURM_ERROR;
+	}
+}
+
+uid_t
+c_slurm_auth_get_uid( slurm_auth_context_t c, void *cred )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) ) return SLURM_AUTH_NOBODY;
+	if ( c->ops.verify ) {
+		return (*(c->ops.get_uid))( cred );
+	} else {
+		return SLURM_AUTH_NOBODY;
+	}
+}
+
+gid_t
+c_slurm_auth_get_gid( slurm_auth_context_t c, void *cred )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) ) return SLURM_AUTH_NOBODY;
+	if ( c->ops.verify ) {
+		return (*(c->ops.get_gid))( cred );
+	} else {
+		return SLURM_AUTH_NOBODY;
+	}
+}
+
+
+void
+c_slurm_auth_pack( slurm_auth_context_t c, void *cred, Buf buf )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) || ( buf == NULL ) )
+		return;
+	if ( c->ops.pack ) {
+		(*(c->ops.pack))( cred, buf );
+	}
+}
+
+
+int
+c_slurm_auth_unpack( slurm_auth_context_t c, void *cred, Buf buf )
+{	
+	if ( ( c == NULL ) || ( cred == NULL ) || ( buf == NULL ) )
+		return SLURM_ERROR;	
+	if ( c->ops.unpack ) {
+		return (*(c->ops.unpack))( cred, buf );
+	} else {
+		return SLURM_ERROR;
+	}
+}
+
+void
+c_slurm_auth_print( slurm_auth_context_t c, void *cred, FILE *fp )
+{
+	if ( ( c == NULL ) || ( cred == NULL ) || ( fp == NULL ) )
+		return;
+	if ( c->ops.print ) {
+		(*(c->ops.print))( cred, fp );
+	}
+}
+
+
+/*
+ * Static bindings for the global authentication context.  The test
+ * of the function pointers is omitted here because the global
+ * context initialization includes a test for the completeness of
+ * the API function dispatcher.
+ */
+	  
+void *
+g_slurm_auth_alloc( void )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't allocate credential - authentication init failed" );
+			return NULL;
+		}
+	}
+
+	return (*(g_context->ops.alloc))();
+}
+
+void
+g_slurm_auth_free( void *cred )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't free credential - authentication init failed" );
+			return;
+		}
+	}
+
+	(*(g_context->ops.free))( cred );
+}
+
+int
+g_slurm_auth_activate( void *cred, int secs )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't activate credential - authentication init failed" );
+			return SLURM_ERROR;
+		}
+	}
+
+	return (*(g_context->ops.activate))( cred, secs );
+}
+
+int
+g_slurm_auth_verify( void *cred )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't verify credential - authentication init failed" );
+			return SLURM_ERROR;
+		}
+	}
+	
+	return (*(g_context->ops.verify))( cred );
+}
+
+uid_t
+g_slurm_auth_get_uid( void *cred )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't get UID - authentication init failed" );
+			return SLURM_AUTH_NOBODY;
+		}
+	}
+	
+	return (*(g_context->ops.get_uid))( cred );
+}
+
+gid_t
+g_slurm_auth_get_gid( void *cred )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't get GID - authentication init failed" );
+			return SLURM_AUTH_NOBODY;
+		}
+	}
+	
+	return (*(g_context->ops.get_gid))( cred );
+}
+
+void
+g_slurm_auth_pack( void *cred, Buf buf )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't pack credential - authentication init failed" );
+			return;
+		}
+	}
+	
+	(*(g_context->ops.pack))( cred, buf );
+}
+
+int
+g_slurm_auth_unpack( void *cred, Buf buf )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't unpack credential - authentication init failed" );
+			return SLURM_ERROR;
+		}
+	}
+	
+	return (*(g_context->ops.unpack))( cred, buf );
+}
+
+void
+g_slurm_auth_print( void *cred, FILE *fp )
+{
+	if ( ! g_context ) {
+		if ( slurm_auth_init() != SLURM_SUCCESS ) {
+			error( "can't print credential - authentication init failed" );
+			return;
+		}
+	}
+	
+	(*(g_context->ops.print))( cred, fp );
+}
diff --git a/src/common/slurm_auth.h b/src/common/slurm_auth.h
index 370037d1b20fe46833e829e507d399cd9660ad9e..57104a413da96da573bb46679c0ef653c11fdbad 100644
--- a/src/common/slurm_auth.h
+++ b/src/common/slurm_auth.h
@@ -27,6 +27,8 @@
 #ifndef __SLURM_AUTHENTICATION_H__
 #define __SLURM_AUTHENTICATION_H__
 
+#include <stdio.h>
+
 #if HAVE_CONFIG_H
 #  include "config.h"
 #  if HAVE_INTTYPES_H
@@ -40,58 +42,97 @@
 #  include <inttypes.h>
 #endif  /*  HAVE_CONFIG_H */
 
+#include "src/common/plugrack.h"
 #include "src/common/pack.h"
 
-
-/* slurm_auth_credentials_t is an opaque type whose definition is to
- * be completed in the implementation specific module
+/*
+ * This is really two APIs.  We provide an authentication context object
+ * which can be bound to any authentication type available in the system
+ * and several of which may happily exist together.  The API thunks with
+ * a "c_" prefix operate on these.  The typical order of calls is:
+ *
+ * 	slurm_auth_context_t foo = slurm_auth_context_create( my type );
+ *     	void *bar = c_slurm_auth_alloc( foo );
+ *	c_slurm_auth_activate( foo, bar, 1 );
+ *	c_slurm_auth_verify( foo, bar );
+ *	c_slurm_auth_free( foo, bar );
+ *	slurm_auth_context_destroy( foo );
+ *
+ * There is also a parallel API operating on a global authentication
+ * context, one per application.  The API thunks with the "g_" prefix
+ * operate on that global instance.  It is initialized implicitly if
+ * necessary when any API thunk is called, or explicitly with
+ *
+ *	slurm_auth_init();
+ *
+ * The authentication type and other parameters are taken from the
+ * system's global configuration.  A typical order of calls is:
+ *
+ *	void *bar = g_slurm_auth_alloc();
+ *	g_slurm_auth_activate( bar, 1 );
+ *	g_slurm_auth_verify( bar );
+ *	g_slurm_auth_free( bar );
+ *
  */
-typedef struct slurm_auth_credentials * slurm_auth_t;
 
 /*
- * Allocation a new set of credentials from the free store.  Returns
- * NULL if no allocation is possible.
+ * SLURM authentication context opaque type.
  */
-slurm_auth_t slurm_auth_alloc_credentials( void );
+typedef struct slurm_auth_context * slurm_auth_context_t;
 
 /*
- * Deallocate credentials allocated with slurm_auth_alloc_credentials().
+ * Create an authentication context.
+ *
+ * Returns NULL on failure.
  */
-void slurm_auth_free_credentials( slurm_auth_t cred );
+slurm_auth_context_t slurm_auth_context_create( const char *auth_type );
 
 /*
- * Populate the credentials and validate them for use.
- * cred - The credential to activate.
- * seconds_to_live - the number of seconds after validation that
- *	the credential expires
- * Returns SLURM_ERROR if the credentials could not be populated,
- * validated, or if the authentication daemon is not running.
+ * Destroy an authentication context.  Any jumptables returned by
+ * calls to slurm_auth_get_ops() for this context will silently become
+ * invalid, and calls to their functions may result in core dumps and
+ * other nasty behavior.
+ *
+ * Returns a SLURM errno.
  */
-int slurm_auth_activate_credentials( slurm_auth_t cred,
-				     time_t seconds_to_live );
+int slurm_auth_context_destroy( slurm_auth_context_t ctxt );
 
 /*
- * Verify the credentials.  Returns SLURM_ERROR if the credentials are
- * invalid or has expired.
+ * This is what the UID and GID accessors return on error.  The value
+ * is currently RedHat Linux's ID for the user "nobody".
  */
-int slurm_auth_verify_credentials( slurm_auth_t cred );
+#define SLURM_AUTH_NOBODY		99
 
 /*
- * Extract user and group identification from the credentials.
- * They are trustworthy only if the credentials have first been
- * verified.
+ * Static bindings for an arbitrary authentication context.  We avoid
+ * exposing the API directly to avoid object lifetime issues.
  */
-uid_t slurm_auth_uid( slurm_auth_t cred );
-gid_t slurm_auth_gid( slurm_auth_t cred );
+void	*c_slurm_auth_alloc( slurm_auth_context_t c );
+void	c_slurm_auth_free( slurm_auth_context_t c, void *cred );
+int	c_slurm_auth_activate( slurm_auth_context_t c, void *cred, int secs );
+int	c_slurm_auth_verify( slurm_auth_context_t c, void *cred );
+uid_t	c_slurm_auth_get_uid( slurm_auth_context_t c, void *cred );
+gid_t	c_slurm_auth_get_gid( slurm_auth_context_t c, void *cred );
+void	c_slurm_auth_pack( slurm_auth_context_t c, void *cred, Buf buf );
+int	c_slurm_auth_unpack( slurm_auth_context_t c, void *cred, Buf buf );
+void	c_slurm_auth_print( slurm_auth_context_t c, void *cred, FILE *fp );
 
 /*
- * Methods for packing and unpacking the credentials for transport.
+ * Prepare the global context.
  */
-void slurm_auth_pack_credentials( slurm_auth_t cred, Buf buffer );
-int  slurm_auth_unpack_credentials( slurm_auth_t *cred, Buf buffer );
+int slurm_auth_init( void );
 
-#if DEBUG
-void slurm_auth_print_credentials( slurm_auth_t *cred );
-#endif
+/*
+ * Static bindings for the global authentication context.
+ */
+void	*g_slurm_auth_alloc( void );
+void	g_slurm_auth_free( void *cred );
+int	g_slurm_auth_activate( void *cred, int secs );
+int	g_slurm_auth_verify( void *cred );
+uid_t	g_slurm_auth_get_uid( void *cred );
+gid_t	g_slurm_auth_get_gid( void *cred );
+void	g_slurm_auth_pack( void *cred, Buf buf );
+int	g_slurm_auth_unpack( void *cred, Buf buf );
+void	g_slurm_auth_print( void *cred, FILE *fp );
 
 #endif /*__SLURM_AUTHENTICATION_H__*/
diff --git a/src/common/slurm_auth_authd.c b/src/common/slurm_auth_authd.c
deleted file mode 100644
index 84df98d372e58f5d74325eefbd73f6528cd1554e..0000000000000000000000000000000000000000
--- a/src/common/slurm_auth_authd.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*****************************************************************************\
- *  slurm_auth_authd.c - authentication module for Brent Chun's authd
- *****************************************************************************
- *  Copyright (C) 2002 The Regents of the University of California.
- *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
- *  Written by Keven Tew <tew1@llnl.gov>.
- *  UCRL-CODE-2002-040.
- *  
- *  This file is part of SLURM, a resource management program.
- *  For details, see <http://www.llnl.gov/linux/slurm/>.
- *  
- *  SLURM is free software; you can redistribute it and/or modify it under
- *  the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *  
- *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
- *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- *  details.
- *  
- *  You should have received a copy of the GNU General Public License along
- *  with SLURM; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
-\*****************************************************************************/
-
-#if HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <pwd.h>
-#include <grp.h>
-
-#if HAVE_SSL
-#  include <openssl/rsa.h>
-#  include <openssl/pem.h>
-#  include <openssl/err.h>
-#endif
-
-/*
- * Because authd's authentication scheme relies on determining the
- * owner of a Unix domain socket over which the request is made to
- * authenticate credentials, we must do our own socket thing unless
- * the transport abstraction layer will provide for Unix domain
- * sockets.
- */
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <slurm/slurm_errno.h>
-
-#include "src/common/log.h"
-#include "src/common/pack.h"
-#include "src/common/slurm_auth.h"
-#include "src/common/xmalloc.h"
-
-#define UNIX_PATH_MAX 108    /* Cribbed from /usr/include/linux/un.h */
-
-#if HAVE_AUTHD
-#  include <auth.h>
-/* Completion of slurm_auth_credentials_t from slurm_auth.h 
- */
-typedef struct slurm_auth_credentials {
-	credentials creds;	/* Authd's credential structure. */
-	signature sig;		/* RSA hash for the credentials. */
-} slurm_auth_credentials_t;
-#else /* !HAVE_AUTHD */
-/* XXX: This needs to go away. This module should only be compiled in if
- *      we have authd. 
- */
-#include <sys/types.h>
-#include <time.h>
-
-typedef struct authd_credentials {
-	uid_t uid;
-	gid_t gid;
-	time_t valid_from;
-	time_t valid_to;
-} credentials;
-
-typedef struct authd_signature {
-	unsigned char data[1];
-} signature;
-
-typedef struct slurm_auth_credentials {
-	credentials creds;
-	signature   sig;
-} slurm_auth_credentials_t;
-#endif
-
-static int slurm_sign_auth_credentials( slurm_auth_credentials_t *cred );
-
-slurm_auth_t 
-slurm_auth_alloc_credentials( void )
-{
-	return (slurm_auth_t) xmalloc(sizeof(struct slurm_auth_credentials));
-}
-
-
-void
-slurm_auth_free_credentials( slurm_auth_t cred )
-{
-	xfree( cred );
-}
-
-
-int
-slurm_auth_activate_credentials( slurm_auth_t cred, time_t ttl )
-{
-	int rc;
-	/* Initialize credentials with our user and group IDs. */
-	cred->creds.uid = geteuid();
-	cred->creds.gid = getegid();
-  
-	/* Set the valid time interval. */
-	cred->creds.valid_from = time( NULL );
-	cred->creds.valid_to = cred->creds.valid_from + ttl;
-
-	/* Sign the credentials. */
-	if ((rc = slurm_sign_auth_credentials(cred)) < 0) 
-		return rc;
-		
-	return SLURM_SUCCESS;
-}
-
-
-int
-slurm_auth_verify_credentials( slurm_auth_t cred )
-{
-#ifdef HAVE_AUTHD
-	int rc = auth_verify_signature(&cred->creds, &cred->sig);
-	if (rc < 0) {
-		switch (rc) {
-		 case AUTH_FOPEN_ERROR:
-			 slurm_seterrno_ret(ESLURM_AUTH_FOPEN_ERROR);
-		 case AUTH_RSA_ERROR:
-		 case AUTH_CRED_ERROR:
-			 slurm_seterrno_ret(ESLURM_AUTH_CRED_INVALID);
-		 case AUTH_NET_ERROR:
-			 slurm_seterrno_ret(ESLURM_AUTH_NET_ERROR);
-		 default:
-			 slurm_seterrno_ret(ESLURM_AUTH_CRED_INVALID);
-		}
-	}
-#endif
-	return SLURM_SUCCESS;
-}
-
-
-/* Should really do this with inline accessors. */
-uid_t slurm_auth_uid( slurm_auth_t cred )
-{
-	return cred->creds.uid;
-}
-
-gid_t slurm_auth_gid( slurm_auth_t cred )
-{
-	return cred->creds.gid;
-}
-
-void slurm_auth_pack_credentials( slurm_auth_t cred, Buf buffer)
-{
-	uint16_t chunk_size = sizeof( signature );
-  
-	pack32   ( cred->creds.uid,            buffer );
-	pack32   ( cred->creds.gid,            buffer );
-	pack_time( cred->creds.valid_from,     buffer );
-	pack_time( cred->creds.valid_to,       buffer );
-	packmem  ( cred->sig.data, chunk_size, buffer );
-}
-
-
-int slurm_auth_unpack_credentials( slurm_auth_t *credp, Buf buffer)
-{
-	uint16_t dummy;
-	char *data;
-	slurm_auth_t cred;
-
-	cred = slurm_auth_alloc_credentials();
-	safe_unpack32     ( &cred->creds.uid,        buffer );
-	safe_unpack32     ( &cred->creds.gid,        buffer );
-	safe_unpack_time  ( &cred->creds.valid_from, buffer );
-	safe_unpack_time  ( &cred->creds.valid_to,   buffer );
-	safe_unpackmem_ptr( &data, &dummy,           buffer );
-	memcpy( cred->sig.data, data, sizeof( signature ) );
-	*credp = cred;
-	return SLURM_SUCCESS;
-
-    unpack_error:
-	slurm_auth_free_credentials( cred );
-	*credp = NULL;
-	return SLURM_ERROR;
-}
-
-
-static int
-slurm_sign_auth_credentials( slurm_auth_t cred )
-{
-#ifdef HAVE_AUTHD
-	assert(cred != NULL);
-	return auth_get_signature(&cred->creds, &cred->sig);
-#else
-	return SLURM_SUCCESS;
-#endif
-}
-
-#if DEBUG
-void
-slurm_auth_print_credentials( slurm_auth_credentials_t *cred )
-{
-	struct passwd *pwent;
-	struct group *grent;
-	int i;
-  
-	printf( "-- BEGIN CLIENT CREDENTIALS\n" );
-	pwent = getpwuid( cred->creds.uid );
-	printf( "       user : %d (%s)\n",
-		cred->creds.uid,
-		pwent ? pwent->pw_name : "unknown" );
-	grent = getgrgid( cred->creds.gid );
-	printf( "      group : %d (%s)\n",
-		cred->creds.gid,
-		grent ? grent->gr_name : "unknown" );
-  
-	printf( "  effective : %ld %s",
-		cred->creds.valid_from,
-		ctime( &cred->creds.valid_from ) );
-	printf( "    expires : %ld %s",
-		cred->creds.valid_to,
-		ctime( &cred->creds.valid_to ) );
-	printf( "  signature :" );
-	for ( i = 0; i < sizeof( cred->sig.data ); ++i ) {
-		if ( ( i % 16 ) == 0 ) printf( "\n    " );
-		if ( ( i % 4 ) == 0 ) putchar( ' ' );
-		printf( "%02x", cred->sig.data[ i ] );
-	}
-	printf( "\n-- END CLIENT CREDENTIALS\n" );
-}
-#endif /*DEBUG*/
diff --git a/src/common/slurm_protocol_api.c b/src/common/slurm_protocol_api.c
index b714ac5c25a4830588ed257e6c091a01c1bf2dc3..3a0b78bfa79dbeae57644378d491315545411599 100644
--- a/src/common/slurm_protocol_api.c
+++ b/src/common/slurm_protocol_api.c
@@ -257,6 +257,7 @@ slurm_fd slurm_open_controller_conn()
 			debug
 			    ("Open connection to secondary controller failed: %m");
 	}
+
 	return connection_fd;
 }
 
@@ -332,7 +333,7 @@ int slurm_receive_msg(slurm_fd open_fd, slurm_msg_t * msg)
 	char *buftemp;
 	header_t header;
 	int rc;
-	slurm_auth_t creds;
+	void *auth_cred;
 	Buf buffer;
 
 	buftemp = xmalloc(SLURM_PROTOCOL_MAX_MESSAGE_BUFFER_SIZE);
@@ -343,6 +344,9 @@ int slurm_receive_msg(slurm_fd open_fd, slurm_msg_t * msg)
 		xfree(buftemp);
 		return rc;
 	}
+
+	auth_cred = g_slurm_auth_alloc();
+	
 #if	_DEBUG
 	 _print_data (buftemp,rc);
 #endif
@@ -355,15 +359,15 @@ int slurm_receive_msg(slurm_fd open_fd, slurm_msg_t * msg)
 		slurm_seterrno_ret(SLURM_PROTOCOL_VERSION_ERROR);
 	}
 
-	/* unpack cred */
-	if (slurm_auth_unpack_credentials(&creds, buffer)) {
+	/* unpack authentication cred */
+	if (g_slurm_auth_unpack( auth_cred, buffer)) {
 		free_buf(buffer);
 		slurm_seterrno_ret(ESLURM_PROTOCOL_INCOMPLETE_PACKET);
 	}
 
 	/* verify credentials */
-	if ((rc = slurm_auth_verify_credentials(creds)) != SLURM_SUCCESS) {
-		slurm_auth_free_credentials(creds);
+	if ((rc = g_slurm_auth_verify(auth_cred)) != SLURM_SUCCESS) {
+		g_slurm_auth_free(auth_cred);
 		free_buf(buffer);
 		slurm_seterrno_ret(SLURM_PROTOCOL_AUTHENTICATION_ERROR);
 	}
@@ -372,14 +376,12 @@ int slurm_receive_msg(slurm_fd open_fd, slurm_msg_t * msg)
 	msg->msg_type = header.msg_type;
 	if ((header.body_length > remaining_buf(buffer)) ||
 	    (unpack_msg(msg, buffer) != SLURM_SUCCESS)) {
-		slurm_auth_free_credentials(creds);
+		g_slurm_auth_free(auth_cred);
 		free_buf(buffer);
 		slurm_seterrno_ret(ESLURM_PROTOCOL_INCOMPLETE_PACKET);
 	}
 
-	msg->cred = (void *) creds;
-	msg->cred_type = header.cred_type;
-	msg->cred_size = header.cred_length;
+	msg->cred = (void *) auth_cred;
 
 	free_buf(buffer);
 	return SLURM_SUCCESS;
@@ -424,19 +426,16 @@ int slurm_send_node_msg(slurm_fd open_fd, slurm_msg_t * msg)
 {
 	header_t header;
 	int rc;
-	unsigned int cred_len, msg_len, tmp_len;
+	unsigned int msg_len, tmp_len;
 	Buf buffer;
-	slurm_auth_t creds = slurm_auth_alloc_credentials();
-
-	if (creds == NULL)
-		error("unable to alloc credentials");
+	void *auth_cred;
 
 	/* initialize header */
+	auth_cred = g_slurm_auth_alloc();
 	init_header(&header, msg->msg_type, SLURM_PROTOCOL_NO_FLAGS);
-	rc = slurm_auth_activate_credentials(creds, CREDENTIAL_TTL_SEC);
+	rc = g_slurm_auth_activate(auth_cred, CREDENTIAL_TTL_SEC);
 	if (rc != SLURM_SUCCESS)	/* Try once more */
-		rc = slurm_auth_activate_credentials(creds, 
-						     CREDENTIAL_TTL_SEC);
+		rc = g_slurm_auth_activate(auth_cred, CREDENTIAL_TTL_SEC);
 	if (rc != SLURM_SUCCESS) {
 		error
 		    ("slurm_send_node_msg: sending msg with unsigned credential, rc=%d)",
@@ -448,10 +447,8 @@ int slurm_send_node_msg(slurm_fd open_fd, slurm_msg_t * msg)
 	pack_header(&header, buffer);
 
 	/* pack creds */
-	tmp_len = get_buf_offset(buffer);
-	slurm_auth_pack_credentials(creds, buffer);
-	slurm_auth_free_credentials(creds);
-	cred_len = get_buf_offset(buffer) - tmp_len;
+	g_slurm_auth_pack(auth_cred, buffer);
+	g_slurm_auth_free(auth_cred);
 
 	/* pack msg */
 	tmp_len = get_buf_offset(buffer);
@@ -459,7 +456,8 @@ int slurm_send_node_msg(slurm_fd open_fd, slurm_msg_t * msg)
 	msg_len = get_buf_offset(buffer) - tmp_len;
 
 	/* update header with correct cred and msg lengths */
-	update_header(&header, cred_len, msg_len);
+	update_header(&header, msg_len);
+	
 	/* repack updated header */
 	tmp_len = get_buf_offset(buffer);
 	set_buf_offset(buffer, 0);
@@ -763,8 +761,9 @@ int slurm_send_recv_controller_msg(slurm_msg_t * request_msg,
 	int error_code = 0;
 
 	/* init message connection for communication with controller */
-	if ((sockfd = slurm_open_controller_conn()) == SLURM_SOCKET_ERROR)
+	if ((sockfd = slurm_open_controller_conn()) == SLURM_SOCKET_ERROR) {
 		return SLURM_SOCKET_ERROR;
+	}
 
 	/* send request message */
 	if ((rc =
@@ -913,6 +912,6 @@ int slurm_send_only_node_msg(slurm_msg_t * request_msg)
 /* Slurm message functions */
 void slurm_free_msg(slurm_msg_t * msg)
 {
-	slurm_auth_free_credentials((slurm_auth_t) msg->cred);
+	g_slurm_auth_free(msg->cred);
 	xfree(msg);
 }
diff --git a/src/common/slurm_protocol_defs.h b/src/common/slurm_protocol_defs.h
index b52c6900113ef957a332d95282ee8ffa4155b9c6..683830813bbc0357ff658626b54d016464dab247 100644
--- a/src/common/slurm_protocol_defs.h
+++ b/src/common/slurm_protocol_defs.h
@@ -159,8 +159,6 @@ typedef struct slurm_protocol_config {
 typedef struct slurm_protocol_header {
 	uint16_t version;
 	uint16_t flags;
-	slurm_credential_type_t cred_type;
-	uint32_t cred_length;
 	slurm_msg_type_t msg_type;
 	uint32_t body_length;
 } header_t;
@@ -176,9 +174,7 @@ typedef struct slurm_msg {
 	slurm_msg_type_t msg_type;
 	slurm_addr address;
 	slurm_fd conn_fd;
-	slurm_credential_type_t cred_type;
 	void *cred;
-	uint32_t cred_size;
 	void *data;
 	uint32_t data_size;
 } slurm_msg_t;
diff --git a/src/common/slurm_protocol_pack.c b/src/common/slurm_protocol_pack.c
index d94ac91032b5736aca654306719902701cd597e0..135da5dcdc6c0339d1db01d3a4aaaa0c2f044b75 100644
--- a/src/common/slurm_protocol_pack.c
+++ b/src/common/slurm_protocol_pack.c
@@ -209,9 +209,6 @@ pack_header(header_t * header, Buf buffer)
 {
 	pack16(header->version, buffer);
 	pack16(header->flags, buffer);
-	pack16((uint16_t) header->cred_type, buffer);
-
-	pack32(header->cred_length, buffer);
 	pack16((uint16_t) header->msg_type, buffer);
 	pack32(header->body_length, buffer);
 }
@@ -231,10 +228,6 @@ unpack_header(header_t * header, Buf buffer)
 	safe_unpack16(&header->version, buffer);
 	safe_unpack16(&header->flags, buffer);
 	safe_unpack16(&tmp, buffer);
-	header->cred_type = (slurm_credential_type_t) tmp;
-
-	safe_unpack32(&header->cred_length, buffer);
-	safe_unpack16(&tmp, buffer);
 	header->msg_type = (slurm_msg_type_t) tmp;
 	safe_unpack32(&header->body_length, buffer);
 	return SLURM_SUCCESS;
diff --git a/src/common/slurm_protocol_util.c b/src/common/slurm_protocol_util.c
index af8a995d9f83b6726df3f036332e558a0bcfe656..c7f78673905f3e8e87861ab5dda23e8a19bcc948 100644
--- a/src/common/slurm_protocol_util.c
+++ b/src/common/slurm_protocol_util.c
@@ -65,15 +65,12 @@ void init_header(header_t * header, slurm_msg_type_t msg_type,
 }
 
 /*
- * update_header - update a message header with the credential and message len
+ * update_header - update a message header with the message len
  * OUT header - the message header to update
- * IN cred_length - credential length
  * IN msg_length - length of message to be send 
  */
-void update_header(header_t * header, uint32_t cred_length,
-		   uint32_t msg_length)
+void update_header(header_t * header, uint32_t msg_length)
 {
-	header->cred_length = cred_length;
 	header->body_length = msg_length;
 }
 
diff --git a/src/common/slurm_protocol_util.h b/src/common/slurm_protocol_util.h
index 7b73f9d171a12b968912ebe012d4f262c47ca106..8150009e23d071c9be40aceb39c58bf81136a660 100644
--- a/src/common/slurm_protocol_util.h
+++ b/src/common/slurm_protocol_util.h
@@ -87,13 +87,12 @@ init_io_stream_header(slurm_io_stream_header_t * header, char *key,
                       uint32_t task_id, uint16_t type);
 
 /*
- * update_header - update a message header with the credential and message len
+ * update_header - update a message header with the message len
  * OUT header - the message header to update
- * IN cred_length - credential length
  * IN msg_length - length of message to be send 
  */
 extern void 
-update_header(header_t * header, uint32_t cred_length, uint32_t msg_length);
+update_header(header_t * header, uint32_t msg_length);
 
 /*
  * read an i/o stream header from the supplied slurm stream
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..051a35a8f68b8fe512143219d0c45a7719853f01
--- /dev/null
+++ b/src/plugins/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = auth
+
diff --git a/src/plugins/auth/Makefile.am b/src/plugins/auth/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..257e005e7e15fdda43fddf1141e55a57354c9ecc
--- /dev/null
+++ b/src/plugins/auth/Makefile.am
@@ -0,0 +1,22 @@
+# $Id$
+# Makefile for auth plugins
+
+AUTOMAKE_OPTIONS = foreign
+
+PLUGIN_FLAGS = -module -avoid-version
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src/common
+
+# Add your plugin to this line, following the naming conventions.
+lib_LTLIBRARIES = libauth_none.la libauth_authd.la
+
+# Null authentication plugin.
+libauth_none_la_SOURCES = auth_none.c
+libauth_none_la_LDFLAGS = $(PLUGIN_FLAGS)
+libauth_none_la_LIBADD = -lslurm
+
+# Authd authentication plugin -- requires libauth
+libauth_authd_la_SOURCES = auth_authd.c
+libauth_authd_la_LDFLAGS = $(PLUGIN_FLAGS)
+libauth_authd_la_LIBADD = -lslurm -lauth
+
diff --git a/src/plugins/auth/auth_authd.c b/src/plugins/auth/auth_authd.c
new file mode 100644
index 0000000000000000000000000000000000000000..0193f1a8d124865d4a32faac2b3cf1d88881be93
--- /dev/null
+++ b/src/plugins/auth/auth_authd.c
@@ -0,0 +1,347 @@
+/*****************************************************************************\
+ *  auth_authd - plugin for Brent Chun's authd
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Kevin Tew <tew1@llnl.gov> et. al.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#if HAVE_CONFIG_H
+#  include "config.h"
+#  if HAVE_SSL
+#    include <openssl/rsa.h>
+#    include <openssl/pem.h>
+#    include <openssl/err.h>
+#  endif /* HAVE_SSL*/
+#  if STDC_HEADERS
+#    include <stdio.h>
+#    include <string.h>
+#  endif /* STDC_HEADERS */
+#  if HAVE_UNISTD_H
+#    include <unistd.h>
+#  endif /* HAVE_UNISTD_H */
+#else /* ! HAVE_CONFIG_H */
+#  include <stdio.h>
+#  include <unistd.h>
+#  include <string.h>
+#  include <openssl/rsa.h>
+#  include <openssl/pem.h>
+#  include <openssl/err.h>
+#  include <auth.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <pwd.h>
+#include <grp.h>
+#include <auth.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+/* Need these regardless of how main SLURM transport is abstracted. */
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108  /* Cribbed from linux/un.h */
+#endif
+
+#include <slurm/slurm_errno.h>
+#include "src/common/xmalloc.h"
+#include "src/common/xassert.h"
+#include "src/common/pack.h"
+#include "src/common/log.h"
+
+const char plugin_name[]	= "Brett Chun's authd authentication plugin";
+const char plugin_type[]	= "auth/authd";
+const uint32_t plugin_version = 90;
+
+typedef struct _slurm_auth_credential {
+	credentials cred;
+	signature sig;
+} slurm_auth_credential_t;
+
+/*
+ * These come from /usr/include/auth.h which should be installed
+ * as part of the authd installation.
+ */
+static char *cli_path = AUTH_SOCK_PATH;
+static char *svr_path = AUTHD_SOCK_PATH;
+static char *pub_key_file = AUTH_PUB_KEY;
+
+/*
+ * Write bytes reliably to a file descriptor.
+ */
+static int
+write_bytes( int fd, char *buf, size_t size )
+{
+	ssize_t bytes_remaining, bytes_written;
+	char *ptr;
+
+	bytes_remaining = size;
+	ptr = buf;
+	while ( bytes_remaining > 0 ) {
+		bytes_written = write( fd, ptr, size );
+		if ( bytes_written < 0 ) return -1;
+		bytes_remaining -= bytes_written;
+		ptr += bytes_written;
+	}
+	return 0;
+}
+
+/*
+ * Read bytes reliably from a file descriptor.
+ */
+static int
+read_bytes( int fd, char *buf, size_t size )
+{
+	ssize_t bytes_remaining, bytes_read;
+	char *ptr;
+
+	bytes_remaining = size;
+	ptr = buf;
+	while ( bytes_remaining > 0 ) {
+		bytes_read = read( fd, ptr, size );
+		if ( bytes_read < 0 ) return -1;
+		bytes_remaining -= bytes_read;
+		ptr += bytes_read;
+	}
+	return 0;
+}
+
+/*
+ * These two cribbed from auth.c in the authd distribution.  They would
+ * normally be available in the authd library, but the library relies on
+ * Brett Chun's enormous and irrelevant convenience library, and we only
+ * need to make one call to that library here.  So we inline the code
+ * from his library and sever the dependency.
+ */
+static int
+slurm_auth_get_signature( credentials *cred, signature *sig )
+{
+	int sock;
+	char cli_name[ UNIX_PATH_MAX ];
+	struct sockaddr_un cli_addr;
+	struct sockaddr_un svr_addr;
+	socklen_t addr_len = sizeof( struct sockaddr_un );
+
+	if ( ( sock = socket( AF_UNIX, SOCK_STREAM, 0 ) ) < 0 ) {
+		return -1;
+	}
+
+	cli_addr.sun_family = AF_UNIX;	
+	memset( cli_addr.sun_path, 0, UNIX_PATH_MAX );
+	sprintf( cli_name, cli_path, getpid() );
+	strcpy( &cli_addr.sun_path[ 1 ], cli_name );
+	if ( bind( sock, (struct sockaddr *) &cli_addr, addr_len ) < 0 ) {
+		error( "authd plugin: cannot bind socket to authd" );
+		close( sock );
+		return -1;
+	}
+
+	svr_addr.sun_family = AF_UNIX;
+	memset( svr_addr.sun_path, 0, UNIX_PATH_MAX );
+	strcpy( &svr_addr.sun_path[ 1 ], svr_path );
+	if ( connect( sock, (struct sockaddr *) &svr_addr, addr_len ) < 0 ) {
+		error( "suthd plugin: cannot connect to authd" );
+		close( sock );
+		return -1;
+	}
+	
+	if ( write_bytes( sock, (char *) cred, sizeof( credentials ) ) < 0 ) {
+		error( "authd plugin: cannot write to authd" );
+		close( sock );
+		return -1;
+	}
+	if ( read_bytes( sock, (char *) sig, sizeof( signature ) ) < 0 ) {
+		error( "authd plugin: cannot read from authd" );
+		close( sock );
+		return -1;
+	}
+	close( sock );
+	return 0;	
+}
+
+static int
+slurm_auth_verify_signature( credentials *cred, signature *sig )
+{
+	int rc_error = 0;
+	RSA *pub_key = NULL;
+	FILE *f = NULL;
+
+	if ( ( f = fopen( pub_key_file, "r" ) ) == NULL ) {		
+		rc_error = -1;
+		error( "authd plugin: cannot open public key file %s", pub_key_file );
+		goto cleanup;
+	}
+
+	if ( ( pub_key = PEM_read_RSA_PUBKEY( f, NULL, NULL, NULL ) ) == NULL ) {
+		error( "authd plugin: cannot read RSA public key" );
+		rc_error = -1;
+		goto cleanup;
+	}
+
+	ERR_load_crypto_strings();
+	if ( RSA_verify( 0,
+					 (unsigned char *) cred, sizeof( credentials ),
+					 sig->data, AUTH_RSA_SIGLEN,
+					 pub_key ) == 0 ) {
+		rc_error = -1;
+		error( "authd plugin: cannot verify signature" );
+		goto cleanup;
+	}
+
+ cleanup:
+	if ( pub_key != NULL ) RSA_free( pub_key );
+	if ( f != NULL ) fclose( f );
+	return rc_error;
+}
+
+slurm_auth_credential_t *
+slurm_auth_alloc( void )
+{
+	return (slurm_auth_credential_t *) xmalloc( sizeof( slurm_auth_credential_t ) );
+}
+
+void
+slurm_auth_free( slurm_auth_credential_t *cred )
+{
+	if ( cred != NULL ) xfree( cred );
+}
+
+int
+slurm_auth_activate( slurm_auth_credential_t *cred, int ttl )
+{
+	if ( cred == NULL ) return SLURM_ERROR;
+	if ( ttl < 1 ) return SLURM_ERROR;
+	
+	/* Initialize credential with our user and group. */
+	cred->cred.uid = geteuid();
+	cred->cred.gid = getegid();
+
+	/* Set a valid time interval. */
+	cred->cred.valid_from = time( NULL );
+	cred->cred.valid_to = cred->cred.valid_from + ttl;
+
+	/* Sign the credential. */
+	if ( slurm_auth_get_signature( &cred->cred, &cred->sig ) < 0 ) {
+		return SLURM_ERROR;
+	}
+
+	return SLURM_SUCCESS;
+}
+
+int
+slurm_auth_verify( slurm_auth_credential_t *cred )
+{
+	int rc;
+
+	if ( cred == NULL ) return SLURM_ERROR;
+	
+	rc = slurm_auth_verify_signature( &cred->cred, &cred->sig );
+	if ( rc < 0 ) {
+		return SLURM_ERROR;
+	}
+
+	return SLURM_SUCCESS;
+}
+
+
+uid_t
+slurm_auth_get_uid( slurm_auth_credential_t *cred )
+{
+	xassert( cred );
+	return cred->cred.uid;
+}
+
+
+gid_t
+slurm_auth_get_gid( slurm_auth_credential_t *cred )
+{
+	xassert( cred );
+	return cred->cred.gid;
+}
+
+
+void
+slurm_auth_pack( slurm_auth_credential_t *cred, Buf buf )
+{
+	uint16_t sig_size = sizeof( signature );
+
+	if ( ( cred == NULL ) || ( buf == NULL ) ) return;
+
+	/*
+	 * Marshall the plugin type for runtime sanity check.
+	 * Add the terminating zero so we get it for free at the
+	 * other end.
+	 */
+	packmem( (char *) plugin_type, strlen( plugin_type ) + 1, buf );
+	
+	pack32( cred->cred.uid, buf );
+	pack32( cred->cred.gid, buf );
+	pack_time( cred->cred.valid_from, buf );
+	pack_time( cred->cred.valid_to, buf );
+	packmem( cred->sig.data, sig_size, buf );
+}
+
+
+int
+slurm_auth_unpack( slurm_auth_credential_t *cred, Buf buf )
+{
+	uint16_t sig_size; /* ignored */
+	char *data;
+
+	if ( ( cred == NULL) || ( buf == NULL ) )
+		return SLURM_ERROR;
+
+	/* Check the plugin type. */
+	unpackmem_ptr( &data, &sig_size, buf );
+	if ( strcmp( data, plugin_type ) != 0 ) {
+		error( "authd plugin: authentication mismatch, got %s", data );
+		return SLURM_ERROR;
+	}
+	
+	unpack32( &cred->cred.uid, buf );
+	unpack32( &cred->cred.gid, buf );
+	unpack_time( &cred->cred.valid_from, buf );
+	unpack_time( &cred->cred.valid_to, buf );
+	unpackmem_ptr( &data, &sig_size, buf );
+	memcpy( cred->sig.data, data, sizeof( signature ) );
+
+	return SLURM_SUCCESS;
+}
+
+
+void
+slurm_auth_print( slurm_auth_credential_t *cred, FILE *fp )
+{
+	if ( cred == NULL ) return;
+
+	verbose( "BEGIN AUTHD CREDENTIAL\n" );
+	verbose( "   UID: %d", cred->cred.uid );
+	verbose( "   GID: %d", cred->cred.gid );
+	verbose( "   Valid from: %s", ctime( &cred->cred.valid_from ) );
+	verbose( "   Valid to: %s", ctime( &cred->cred.valid_to ) );
+	verbose( "   Signature: 0x%02x%02x%02x%02x ...\n",
+			 cred->sig.data[ 0 ], cred->sig.data[ 1 ],
+			 cred->sig.data[ 2 ], cred->sig.data[ 3 ] );
+	verbose( "END AUTHD CREDENTIAL\n" );
+}
+
diff --git a/src/plugins/auth/auth_none.c b/src/plugins/auth/auth_none.c
new file mode 100644
index 0000000000000000000000000000000000000000..d80ab47f0022c34a74069276a2a5bdc3a27a018f
--- /dev/null
+++ b/src/plugins/auth/auth_none.c
@@ -0,0 +1,296 @@
+/*****************************************************************************\
+ *  auth_none.c - NO-OP slurm authentication plugin, validates all users.
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Kevin Tew <tew1@llnl.gov> et. al.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#if HAVE_CONFIG_H
+#  include "config.h"
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#  if HAVE_SYS_TYPES_H
+#    include <sys/types.h>
+#  endif /* HAVE_SYS_TYPES_H */
+#  if HAVE_UNISTD_H
+#    include <unistd.h>
+#  endif
+#  if HAVE_INTTYPES_H
+#    include <inttypes.h>
+#  else /* ! HAVE_INTTYPES_H */
+#    if HAVE_STDINT_H
+#      include <stdint.h>
+#    endif
+#  endif /* HAVE_INTTYPES_H */
+#else /* ! HAVE_CONFIG_H */
+#  include <sys/types.h>
+#  include <unistd.h>
+#  include <stdint.h>
+#  include <string.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+
+#include <slurm/slurm_errno.h>
+#include "src/common/xassert.h"
+#include "src/common/xmalloc.h"
+#include "src/common/pack.h"
+#include "src/common/log.h"
+#include "src/common/slurm_auth.h"
+
+/*
+ * These variables are required by the generic plugin interface.  If they
+ * are not found in the plugin, the plugin loader will ignore it.
+ *
+ * plugin_name - a string giving a human-readable description of the
+ * plugin.  There is no maximum length, but the symbol must refer to
+ * a valid string.
+ *
+ * plugin_type - a string suggesting the type of the plugin or its
+ * applicability to a particular form of data or method of data handling.
+ * If the low-level plugin API is used, the contents of this string are
+ * unimportant and may be anything.  SLURM uses the higher-level plugin
+ * interface which requires this string to be of the form
+ *
+ *	<application>/<method>
+ *
+ * where <application> is a description of the intended application of
+ * the plugin (e.g., "auth" for SLURM authentication) and <method> is a
+ * description of how this plugin satisfies that application.  SLURM will
+ * only load authentication plugins if the plugin_type string has a prefix
+ * of "auth/".
+ *
+ * plugin_version - an unsigned 32-bit integer giving the version number
+ * of the plugin.  If major and minor revisions are desired, the major
+ * version number may be multiplied by a suitable magnitude constant such
+ * as 100 or 1000.  Various SLURM versions will likely require a certain
+ * minimum versions for their plugins as the authentication API matures.
+ */
+const char plugin_name[]       	= "Null authentication plugin";
+const char plugin_type[]       	= "auth/none";
+const uint32_t plugin_version	= 90;
+
+
+/*
+ * An opaque type representing authentication credentials.  This type can be
+ * called whatever is meaningful and may contain any data required by the
+ * plugin.  However, the plugin must be able to recover the Linux UID and
+ * GID given only an object of this type.
+ *
+ * Since no verification of the credentials is performed in the "none"
+ * authentication, this plugin simply uses the system-supplied UID and GID.
+ * In a more robust authentication context, this might include tickets or
+ * other signatures which the functions of this API can use to conduct
+ * verification.
+ *
+ * The client code never sees the inside of this structure directly.
+ * Objects of this type are passed in and out of the plugin via
+ * anonymous pointers.  Because of this, robust plugins may wish to add
+ * some form of runtime typing to ensure that the pointers they have
+ * received are actually appropriate credentials and not pointers to
+ * random memory.
+ */
+typedef struct _slurm_auth_credential {
+	uid_t uid;
+	gid_t gid;
+} slurm_auth_credential_t;
+
+void init ( void )
+{
+	printf( "hello\n" );
+}
+
+/*
+ * The remainder of this file implements the standard SLURM authentication
+ * API.
+ */
+
+/*
+ * Allocate a credential.  This function should return NULL if it cannot
+ * allocate a credential.  Whether the credential is populated with useful
+ * data at this time is implementation-dependent.
+ */
+slurm_auth_credential_t *
+slurm_auth_alloc( void )
+{
+	return (slurm_auth_credential_t *) xmalloc( sizeof( slurm_auth_credential_t ) );
+}
+
+/*
+ * Free a credential that was allocated with slurm_auth_alloc().
+ */
+void
+slurm_auth_free( slurm_auth_credential_t *cred )
+{
+	if ( cred != NULL ) xfree( cred );
+}
+
+/*
+ * Prepare a credential for use as an authentication token.  Accessor
+ * functions (slurm_auth_get_uid() and slurm_auth_get_gid()) are not required
+ * to return valid data until this function has been called successfully
+ * for the credential.
+ *
+ * secs - the number of seconds for which this credential is deemed
+ * valid; not appropriate to this plugin but essential to others.
+ *
+ * Return SLURM_SUCCESS if the credential is successfully activated.
+ */
+int
+slurm_auth_activate( slurm_auth_credential_t *cred, int secs )
+{
+	if ( cred == NULL ) return SLURM_ERROR;
+	cred->uid = geteuid();
+	cred->gid = getegid();
+	return SLURM_SUCCESS;
+}
+
+/*
+ * Verify a credential to approve or deny authentication.
+ *
+ * Return SLURM_SUCCESS if the credential is in order and valid.
+ */
+int
+slurm_auth_verify( slurm_auth_credential_t *cred )
+{
+	return SLURM_SUCCESS;
+}
+
+/*
+ * Obtain the Linux UID from the credential.  The accuracy of this data
+ * is not assured until slurm_auth_activate() and slurm_auth_verify()
+ * have been called for it in that order.  A plugin may choose to
+ * enforce this call order by adding bookkeeping to its implementation
+ * of slurm_auth_credential_t, but SLURM will guarantee to issue the
+ * proper sequence of calls.
+ */
+uid_t
+slurm_auth_get_uid( slurm_auth_credential_t *cred )
+{
+	if ( cred == NULL ) {
+		return SLURM_AUTH_NOBODY;
+	} else {
+		return cred->uid;
+	}
+}
+
+/*
+ * Obtain the Linux GID from the credential.  See slurm_auth_get_uid()
+ * above for details on correct behavior.
+ */
+gid_t
+slurm_auth_get_gid( slurm_auth_credential_t *cred )
+{
+	if ( cred == NULL ) {
+		return SLURM_AUTH_NOBODY;
+	} else {
+		return cred->gid;
+	}
+}
+
+/*
+ * Marshall a credential for transmission over the network, according to
+ * SLURM's marshalling protocol.
+ */
+void
+slurm_auth_pack( slurm_auth_credential_t *cred, Buf buf )
+{
+	if ( ( cred == NULL ) || ( buf == NULL ) ) {
+		error( "malformed slurm_auth_pack call in auth/none plugin" );
+		return;
+	}
+	
+	/*
+	 * Prefix the credential with a description of the credential
+	 * type so that it can be sanity-checked at the receiving end.
+	 */
+	packmem( (char *) plugin_type, strlen( plugin_type ) + 1, buf );
+	/*
+	 * Pack the data values.
+	 */
+	pack32( cred->uid, buf );
+	pack32( cred->gid, buf );
+}
+
+/*
+ * Unmarshall a credential after transmission over the network according
+ * to SLURM's marshalling protocol.
+ */
+int
+slurm_auth_unpack( slurm_auth_credential_t *cred, Buf buf )
+{
+	char *tmpstr;
+	int32_t tmpint;
+	uint16_t size;
+	
+	if ( ( cred == NULL ) || ( buf == NULL ) ) {
+		error( "malformed slurm_auth_unpack call in auth/none plugin" );
+		return SLURM_ERROR;
+	}
+	
+	/*
+	 * Get the authentication type.
+	 */
+	if ( unpackmem_ptr( &tmpstr, &size, buf ) != SLURM_SUCCESS ) {
+		error( "cannot unpack authentication type: %m" );
+		return SLURM_ERROR;
+	}
+	if ( strcmp( tmpstr, plugin_type ) != 0 ) {
+		error( "runtime authentication plugin type mismatch" );
+		error( "plugin expected 'auth/none' and got '%s'", tmpstr );
+		return SLURM_ERROR;
+	}
+
+	/*
+	 * We do it the hard way because we don't know anything about the
+	 * size of uid_t or gid_t, only that they are integer values.  We
+	 * pack them as 32-bit integers, but we can't pass addresses to them
+	 * directly to unpack as 32-bit integers because there will be bad
+	 * clobbering if they really aren't.  This technique ensures a
+	 * warning at compile time if the sizes are incompatible.
+	 */
+	if ( unpack32( &tmpint, buf ) != SLURM_SUCCESS ) return SLURM_ERROR;
+	cred->uid = tmpint;
+	if ( unpack32( &tmpint, buf ) != SLURM_SUCCESS ) return SLURM_ERROR;
+	cred->gid = tmpint;
+
+	return SLURM_SUCCESS;
+}
+
+/*
+ * Print to a stdio stream a human-readable representation of the
+ * credential for debugging or logging purposes.  The format is left
+ * to the imagination of the plugin developer.
+ */
+void
+slurm_auth_print( slurm_auth_credential_t *cred, FILE *fp )
+{
+	if ( ( cred == NULL) || ( fp == NULL ) ) {
+		return;
+	}
+
+	printf( "BEGIN SLURM BASIC AUTHENTICATION CREDENTIAL\n" );
+	printf( "\tUID = %d\n", cred->uid );
+	printf( "\tGID = %d\n", cred->gid );
+	printf( "END SLURM BASIC AUTHENTICATION CREDENTIAL\n" );
+}
diff --git a/src/slurmctld/Makefile.am b/src/slurmctld/Makefile.am
index 59e819629fc622f60168307d3a3e3bad3cfbb284..1b2a6a99d82a3dcae98510afcda63574592852b9 100644
--- a/src/slurmctld/Makefile.am
+++ b/src/slurmctld/Makefile.am
@@ -31,6 +31,8 @@ slurmctld_SOURCES = 	\
 	read_config.c	\
 	step_mgr.c
 
+slurmctld_LDFLAGS = -export-dynamic
+
 force:
 $(slurmctld_LDADD) : force
 	@cd `dirname $@` && $(MAKE) `basename $@`
diff --git a/src/slurmctld/controller.c b/src/slurmctld/controller.c
index 9afc0de902088f53ab9b145cf357bac9f468646a..920dd1953750f20bc3f69837a3e732cd4c33cbd0 100644
--- a/src/slurmctld/controller.c
+++ b/src/slurmctld/controller.c
@@ -465,7 +465,7 @@ static void *_service_connection(void *arg)
 
 	if ((error_code = slurm_receive_msg(newsockfd, msg))
 	    == SLURM_SOCKET_ERROR) {
-		error("slurm_receive_msg error %m");
+		error("slurm_receive_msg (_service_connection) error %m");
 	} else {
 		if (msg->msg_type == REQUEST_SHUTDOWN_IMMEDIATE)
 			return_code = (void *) "fini";
@@ -956,7 +956,7 @@ static void _slurm_rpc_job_step_kill(slurm_msg_t * msg)
 
 	start_time = clock();
 	debug("Processing RPC: REQUEST_CANCEL_JOB_STEP");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	lock_slurmctld(job_write_lock);
 
 	/* do RPC call */
@@ -1027,7 +1027,7 @@ static void _slurm_rpc_job_step_complete(slurm_msg_t * msg)
 	/* init */
 	start_time = clock();
 	debug("Processing RPC: REQUEST_COMPLETE_JOB_STEP");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	lock_slurmctld(job_write_lock);
 
 	/* do RPC call */
@@ -1193,7 +1193,7 @@ static void _slurm_rpc_update_job(slurm_msg_t * msg)
 	unlock_slurmctld(job_write_lock);
 
 	/* do RPC call */
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	error_code = update_job(job_desc_msg, uid);
 
 	/* return result */
@@ -1231,7 +1231,7 @@ static void _slurm_rpc_update_node(slurm_msg_t * msg)
 
 	start_time = clock();
 	debug("Processing RPC: REQUEST_UPDATE_NODE");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
 		error("Security violation, UPDATE_NODE RPC from uid %u",
@@ -1282,7 +1282,7 @@ static void _slurm_rpc_update_partition(slurm_msg_t * msg)
 
 	start_time = clock();
 	debug("Processing RPC: REQUEST_UPDATE_PARTITION");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
 		error
@@ -1338,7 +1338,7 @@ static void _slurm_rpc_submit_batch_job(slurm_msg_t * msg)
 
 	/* do RPC call */
 	dump_job_desc(job_desc_msg);
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != job_desc_msg->user_id) &&
 	    (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
@@ -1402,7 +1402,7 @@ static void _slurm_rpc_allocate_resources(slurm_msg_t * msg)
 
 	/* do RPC call */
 	dump_job_desc(job_desc_msg);
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != job_desc_msg->user_id) &&
 	    (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
@@ -1475,7 +1475,7 @@ static void _slurm_rpc_allocate_and_run(slurm_msg_t * msg)
 
 	/* do RPC call */
 	dump_job_desc(job_desc_msg);
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != job_desc_msg->user_id) &&
 	    (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
@@ -1575,7 +1575,7 @@ static void _slurm_rpc_old_job_alloc(slurm_msg_t * msg)
 	debug("Processing RPC: REQUEST_OLD_JOB_RESOURCE_ALLOCATION");
 
 	/* do RPC call */
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != job_desc_msg->uid) && (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
 		error("Security violation, RESOURCE_ALLOCATE from uid %u",
@@ -1643,7 +1643,7 @@ static void _slurm_rpc_job_will_run(slurm_msg_t * msg)
 
 	/* do RPC call */
 	dump_job_desc(job_desc_msg);
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != job_desc_msg->user_id) &&
 	    (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
@@ -1678,7 +1678,7 @@ static void _slurm_rpc_ping(slurm_msg_t * msg)
 {
 	/* init */
 	int error_code = SLURM_SUCCESS;
-	uid_t uid = slurm_auth_uid(msg->cred);
+	uid_t uid = g_slurm_auth_get_uid(msg->cred);
 
 	if ((uid != 0) && (uid != getuid())) {
 		error("Security violation, PING RPC from uid %u",
@@ -1706,7 +1706,7 @@ static void _slurm_rpc_reconfigure_controller(slurm_msg_t * msg)
 
 	start_time = clock();
 	debug("Processing RPC: REQUEST_RECONFIGURE");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error("Security violation, RECONFIGURE RPC from uid %u",
 		      (unsigned int) uid);
@@ -1761,7 +1761,7 @@ static void _slurm_rpc_shutdown_controller(slurm_msg_t * msg)
 		READ_LOCK, NO_LOCK
 	};
 
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error("Security violation, SHUTDOWN RPC from uid %u",
 		      (unsigned int) uid);
@@ -1814,7 +1814,7 @@ static void _slurm_rpc_shutdown_controller_immediate(slurm_msg_t * msg)
 	int error_code = 0;
 	uid_t uid;
 
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error
 		    ("Security violation, SHUTDOWN_IMMEDIATE RPC from uid %u",
@@ -1850,7 +1850,7 @@ static void _slurm_rpc_job_step_create(slurm_msg_t * msg)
 	start_time = clock();
 	debug("Processing RPC: REQUEST_JOB_STEP_CREATE");
 	dump_step_desc(req_step_msg);
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != req_step_msg->user_id) &&
 	    (uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
@@ -1916,7 +1916,7 @@ static void _slurm_rpc_node_registration(slurm_msg_t * msg)
 
 	start_time = clock();
 	debug("Processing RPC: MESSAGE_NODE_REGISTRATION_STATUS");
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error_code = ESLURM_USER_ID_MISSING;
 		error("Security violation,  NODE_REGISTER RPC from uid %u",
@@ -2302,7 +2302,7 @@ static int _background_process_msg(slurm_msg_t * msg)
 	int error_code = 0;
 	uid_t uid;
 
-	uid = slurm_auth_uid(msg->cred);
+	uid = g_slurm_auth_get_uid(msg->cred);
 	if ((uid != 0) && (uid != getuid())) {
 		error("Security violation, SHUTDOWN RPC from uid %u",
 		      (unsigned int) uid);
diff --git a/src/slurmd/Makefile.am b/src/slurmd/Makefile.am
index 84514f662dc52cd7a79f58de30fbb6296f14683e..8f48ad9b8782f3d9eb3e10ea2d688008888c2435 100644
--- a/src/slurmd/Makefile.am
+++ b/src/slurmd/Makefile.am
@@ -22,7 +22,7 @@ slurmd_LDADD = 					   \
 	$(top_builddir)/src/common/libeio.la       \
 	$(SSL_LIBS) 
 
-	
+
 common_sources = 	        \
 	slurmd.c slurmd.h       \
 	req.c req.h		\
@@ -42,6 +42,8 @@ common_sources = 	        \
 
 slurmd_SOURCES = $(common_sources) $(interconnect_sources)
 
+slurmd_LDFLAGS = -export-dynamic
+
 EXTRA_slurmd_SOURCES = no_interconnect.c elan_interconnect.c
 
 force:
diff --git a/src/slurmd/req.c b/src/slurmd/req.c
index 3c24fca3062db3e811a3ae1e00eaa48cb70c34df..73a3bfcdc65901484221eb8fabc98751f6de262f 100644
--- a/src/slurmd/req.c
+++ b/src/slurmd/req.c
@@ -204,7 +204,7 @@ _rpc_launch_tasks(slurm_msg_t *msg, slurm_addr *cli)
 	bool     super_user = false, run_prolog = false;
 	launch_tasks_request_msg_t *req = msg->data;
 
-	req_uid = slurm_auth_uid(msg->cred);
+	req_uid = g_slurm_auth_get_uid(msg->cred);
 	if ((req_uid == conf->slurm_user_id) || (req_uid == 0))
 		super_user = true;
 	if ((super_user == false) && (req_uid != req->uid)) {
@@ -255,7 +255,7 @@ _rpc_batch_job(slurm_msg_t *msg, slurm_addr *cli)
 {
 	batch_job_launch_msg_t *req = (batch_job_launch_msg_t *)msg->data;
 	int      rc = SLURM_SUCCESS;
-	uid_t    req_uid = slurm_auth_uid(msg->cred);
+	uid_t    req_uid = g_slurm_auth_get_uid(msg->cred);
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
 		error("Security violation, batch launch RPC from uid %u",
@@ -286,7 +286,7 @@ _rpc_batch_job(slurm_msg_t *msg, slurm_addr *cli)
 static void
 _rpc_reconfig(slurm_msg_t *msg, slurm_addr *cli_addr)
 {
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
 		error("Security violation, reconfig RPC from uid %u",
@@ -299,7 +299,7 @@ _rpc_reconfig(slurm_msg_t *msg, slurm_addr *cli_addr)
 static void
 _rpc_shutdown(slurm_msg_t *msg, slurm_addr *cli_addr)
 {
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
 		error("Security violation, shutdown RPC from uid %u",
@@ -313,7 +313,7 @@ static int
 _rpc_ping(slurm_msg_t *msg, slurm_addr *cli_addr)
 {
 	int               rc = SLURM_SUCCESS;
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
 		error("Security violation, ping RPC from uid %u",
@@ -341,7 +341,7 @@ _rpc_kill_tasks(slurm_msg_t *msg, slurm_addr *cli_addr)
 		goto done;
 	} 
 
-	req_uid = slurm_auth_uid(msg->cred);
+	req_uid = g_slurm_auth_get_uid(msg->cred);
 	if ((req_uid != step->uid) && (req_uid != 0)) {
 	       debug("kill req from uid %ld for job %d.%d owned by uid %ld",
 		     req_uid, req->job_id, req->job_step_id, step->uid);       
@@ -429,8 +429,8 @@ _rpc_reattach_tasks(slurm_msg_t *msg, slurm_addr *cli)
 
 	memset(&resp, 0, sizeof(reattach_tasks_response_msg_t));
 	slurm_get_addr(cli, &port, host, sizeof(host));
-	req_uid = slurm_auth_uid(msg->cred);
-	req_gid = slurm_auth_gid(msg->cred);
+	req_uid = g_slurm_auth_get_uid(msg->cred);
+	req_gid = g_slurm_auth_get_gid(msg->cred);
 
 	info("reattach request from %ld@%s for %d.%d", 
 	     req_uid, host, req->job_id, req->job_step_id);
@@ -545,8 +545,8 @@ _job_still_running(uint32_t job_id)
 static void 
 _rpc_revoke_credential(slurm_msg_t *msg, slurm_addr *cli)
 {
-	int   rc      = SLURM_SUCCESS;
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	int   rc	  = SLURM_SUCCESS;
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 	revoke_credential_msg_t *req = (revoke_credential_msg_t *) msg->data;
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
@@ -593,7 +593,7 @@ static void
 _rpc_update_time(slurm_msg_t *msg, slurm_addr *cli)
 {
 	int   rc      = SLURM_SUCCESS;
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 	job_time_msg_t *req = (job_time_msg_t *) msg->data;
 
 	if ((req_uid != conf->slurm_user_id) && (req_uid != 0)) {
diff --git a/src/slurmd/slurmd.c b/src/slurmd/slurmd.c
index 9563e9c1a8b132c5f4fb6a544b6767f101d89b24..1b5b3bb639a1f70090b934d8fe0714e82875aa27 100644
--- a/src/slurmd/slurmd.c
+++ b/src/slurmd/slurmd.c
@@ -168,8 +168,10 @@ main (int argc, char *argv[])
 
 	info("%s started on %T", xbasename(argv[0]));
 
-	if (_slurmd_init() < 0)
+	if (_slurmd_init() < 0) {
+		error( "slurmd initialization failed" );
 		exit(1);
+	}
 
         if (send_registration_msg(SLURM_SUCCESS) < 0) 
 		error("Unable to register with slurm controller");
diff --git a/src/srun/msg.c b/src/srun/msg.c
index 9f9de7dae7cd26504990a4c347f5e973f892b612..090128632921c0ead25acab27cd4e5e91cc4e2b4 100644
--- a/src/srun/msg.c
+++ b/src/srun/msg.c
@@ -426,7 +426,7 @@ _exit_handler(job_t *job, slurm_msg_t *exit_msg)
 static void
 _handle_msg(job_t *job, slurm_msg_t *msg)
 {
-	uid_t req_uid = slurm_auth_uid(msg->cred);
+	uid_t req_uid = g_slurm_auth_get_uid(msg->cred);
 	uid_t uid     = getuid();
 
 	if ((req_uid != slurm_uid) && (req_uid != 0) && (req_uid != uid)) {