97d8b01
diff --git a/.gitignore b/.gitignore
97d8b01
index 6244609..d24d727 100644
97d8b01
--- a/.gitignore
97d8b01
+++ b/.gitignore
97d8b01
@@ -17,18 +17,13 @@ libnfsidmap.pc
97d8b01
 libtool
97d8b01
 .libs/
97d8b01
 libnfsidmap.la
97d8b01
-libnfsidmap_la-cfg.lo
97d8b01
-libnfsidmap_la-libnfsidmap.lo
97d8b01
-libnfsidmap_la-strlcpy.lo
97d8b01
-nss.lo
97d8b01
 nsswitch.la
97d8b01
 static.la
97d8b01
-static.lo
97d8b01
 umich_ldap.la
97d8b01
-umich_ldap.lo
97d8b01
 configure.in~
97d8b01
 m4/
97d8b01
 *.o
97d8b01
+*.lo
97d8b01
 cscope.*
97d8b01
 config.h
97d8b01
 config.h.in
97d8b01
diff --git a/autogen.sh b/autogen.sh
97d8b01
index ee89987..c17f6be 100755
97d8b01
--- a/autogen.sh
97d8b01
+++ b/autogen.sh
97d8b01
@@ -37,5 +37,6 @@ fi
97d8b01
 
97d8b01
 aclocal
97d8b01
 libtoolize --force --copy
97d8b01
-autoupdate
97d8b01
+autoheader
97d8b01
+automake --add-missing --copy --gnu
97d8b01
 autoreconf -vi -Wall
97d8b01
diff --git a/idmapd.conf.5 b/idmapd.conf.5
97d8b01
index 9c7f1ae..de1bfa9 100644
97d8b01
--- a/idmapd.conf.5
97d8b01
+++ b/idmapd.conf.5
97d8b01
@@ -31,7 +31,7 @@
97d8b01
 .\"
97d8b01
 .TH idmapd.conf 5 "19 Nov 2008"
97d8b01
 .SH NAME
97d8b01
-idmapd.conf
97d8b01
+idmapd.conf \- configuration file for libnfsidmap
97d8b01
 .SH SYNOPSIS
97d8b01
 Configuration file for libnfsidmap.  Used by idmapd and svcgssd to map NFSv4 name to and from ids.
97d8b01
 .SH DESCRIPTION
97d8b01
@@ -234,7 +234,6 @@ Number of seconds before timing out an LDAP request
97d8b01
 .\" -------------------------------------------------------------------
97d8b01
 .\"
97d8b01
 .SH EXAMPLES
97d8b01
-."
97d8b01
 An example
97d8b01
 .I /etc/idmapd.conf
97d8b01
 file:
97d8b01
@@ -266,7 +265,7 @@ johndoe@OTHER.DOMAIN.ORG = johnny
97d8b01
 LDAP_server = ldap.domain.org
97d8b01
 LDAP_base = dc=org,dc=domain
97d8b01
 
97d8b01
-.fo
97d8b01
+.fi
97d8b01
 .\"
97d8b01
 .\" -------------------------------------------------------------------
97d8b01
 .\" Additional sections
97d8b01
@@ -275,11 +274,11 @@ LDAP_base = dc=org,dc=domain
97d8b01
 .SH SEE ALSO
97d8b01
 .BR idmapd (8)
97d8b01
 .BR svcgssd (8)
97d8b01
-.".SH COMPATIBILITY
97d8b01
-.".SH STANDARDS
97d8b01
-.".SH ACKNOWLEDGEMENTS
97d8b01
-.".SH AUTHORS
97d8b01
-.".SH HISTORY
97d8b01
+.\".SH COMPATIBILITY
97d8b01
+.\".SH STANDARDS
97d8b01
+.\".SH ACKNOWLEDGEMENTS
97d8b01
+.\".SH AUTHORS
97d8b01
+.\".SH HISTORY
97d8b01
 .SH BUGS
97d8b01
 Report bugs to <nfsv4@linux-nfs.org>
97d8b01
-.".SH CAVEATS
97d8b01
+.\".SH CAVEATS
97d8b01
diff --git a/libnfsidmap.c b/libnfsidmap.c
97d8b01
index 57bb6c3..92bc493 100644
97d8b01
--- a/libnfsidmap.c
97d8b01
+++ b/libnfsidmap.c
97d8b01
@@ -99,8 +99,12 @@ static char * toupper_str(char *s)
97d8b01
 static int id_as_chars(char *name, int *id)
97d8b01
 {
97d8b01
 	long int value = strtol(name, NULL, 10);
97d8b01
-	if (value == 0)
97d8b01
-		return 0;
97d8b01
+
97d8b01
+	if (value == 0) {
97d8b01
+		/* zero value ids are valid */
97d8b01
+		if (strcmp(name, "0") != 0)
97d8b01
+			return 0;
97d8b01
+	}
97d8b01
 	*id = (int)value;
97d8b01
 	return 1;
97d8b01
 }
97d8b01
@@ -285,8 +289,9 @@ int nfs4_init_name_mapping(char *conffile)
97d8b01
 			}
97d8b01
 			buf = malloc(siz);
97d8b01
 			if (buf) {
97d8b01
+				*buf = 0;
97d8b01
 				TAILQ_FOREACH(r, &local_realms->fields, link) {
97d8b01
-					sprintf(buf, "'%s' ", r->field);
97d8b01
+					sprintf(buf+strlen(buf), "'%s' ", r->field);
97d8b01
 				}
97d8b01
 				IDMAP_LOG(1, ("libnfsidmap: Realms list: %s", buf));
97d8b01
 				free(buf);
97d8b01
diff --git a/nss.c b/nss.c
97d8b01
index b2b1227..f8129fe 100644
97d8b01
--- a/nss.c
97d8b01
+++ b/nss.c
97d8b01
@@ -135,7 +135,7 @@ static char *strip_domain(const char *name, const char *domain)
97d8b01
 	char *l = NULL;
97d8b01
 	int len;
97d8b01
 
97d8b01
-	c = strchr(name, '@');
97d8b01
+	c = strrchr(name, '@');
97d8b01
 	if (c == NULL && domain != NULL)
97d8b01
 		goto out;
97d8b01
 	if (c == NULL && domain == NULL) {
97d8b01
diff --git a/static.c b/static.c
97d8b01
index fffd458..8be87e8 100644
97d8b01
--- a/static.c
97d8b01
+++ b/static.c
97d8b01
@@ -40,6 +40,7 @@
97d8b01
 #include <grp.h>
97d8b01
 #include <errno.h>
97d8b01
 
97d8b01
+#include "queue.h"
97d8b01
 #include "cfg.h"
97d8b01
 #include "nfsidmap.h"
97d8b01
 #include "nfsidmap_internal.h"
97d8b01
@@ -57,6 +58,40 @@ struct pwbuf {
97d8b01
 	char buf[1];
97d8b01
 };
97d8b01
 
97d8b01
+struct grbuf {
97d8b01
+	struct group grbuf;
97d8b01
+	char buf[1];
97d8b01
+};
97d8b01
+
97d8b01
+struct uid_mapping {
97d8b01
+	LIST_ENTRY (uid_mapping) link;
97d8b01
+	uid_t uid;
97d8b01
+	char * principal;
97d8b01
+	char * localname;
97d8b01
+};
97d8b01
+
97d8b01
+struct gid_mapping {
97d8b01
+	LIST_ENTRY (gid_mapping) link;
97d8b01
+	gid_t gid;
97d8b01
+	char * principal;
97d8b01
+	char * localgroup;
97d8b01
+};
97d8b01
+
97d8b01
+static __inline__ u_int8_t uid_hash (uid_t uid)
97d8b01
+{
97d8b01
+	return uid % 256;
97d8b01
+}
97d8b01
+
97d8b01
+static __inline__ u_int8_t gid_hash (gid_t gid)
97d8b01
+{
97d8b01
+	return gid % 256;
97d8b01
+}
97d8b01
+
97d8b01
+//Hash tables of uid and guids to principals mappings.
97d8b01
+//We reuse some queue/hash functions from cfg.c.
97d8b01
+LIST_HEAD (uid_mappings, uid_mapping) uid_mappings[256];
97d8b01
+LIST_HEAD (gid_mappings, gid_mapping) gid_mappings[256];
97d8b01
+
97d8b01
 static struct passwd *static_getpwnam(const char *name, const char *domain,
97d8b01
 				      int *err_p)
97d8b01
 {
97d8b01
@@ -75,12 +110,9 @@ static struct passwd *static_getpwnam(const char *name, const char *domain,
97d8b01
 	localname = conf_get_str("Static", (char *)name);
97d8b01
 	if (!localname) {
97d8b01
 		err = ENOENT;
97d8b01
-		goto err;
97d8b01
+		goto err_free_buf;
97d8b01
 	}
97d8b01
 
97d8b01
-	IDMAP_LOG(4, ("static_getpwnam: name '%s' mapped to '%s'\n",
97d8b01
-		  name, localname));
97d8b01
-
97d8b01
 again:
97d8b01
 	err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw;;
97d8b01
 
97d8b01
@@ -91,12 +123,15 @@ again:
97d8b01
 		if (err == 0)
97d8b01
 			err = ENOENT;
97d8b01
 
97d8b01
-		IDMAP_LOG(0, ("static_getpwnam: name '%s' not found\n",
97d8b01
-			  localname));
97d8b01
+		IDMAP_LOG(0, ("static_getpwnam: localname '%s' for '%s' not found\n",
97d8b01
+		  localname, name));
97d8b01
 
97d8b01
 		goto err_free_buf;
97d8b01
 	}
97d8b01
 
97d8b01
+	IDMAP_LOG(4, ("static_getpwnam: name '%s' mapped to '%s'\n",
97d8b01
+		  name, localname));
97d8b01
+
97d8b01
 	*err_p = 0;
97d8b01
 	return pw;
97d8b01
 
97d8b01
@@ -107,6 +142,56 @@ err:
97d8b01
 	return NULL;
97d8b01
 }
97d8b01
 
97d8b01
+static struct group *static_getgrnam(const char *name, const char *domain,
97d8b01
+				      int *err_p)
97d8b01
+{
97d8b01
+	struct group *gr;
97d8b01
+	struct grbuf *buf;
97d8b01
+	size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
97d8b01
+	char *localgroup;
97d8b01
+	int err;
97d8b01
+
97d8b01
+	buf = malloc(sizeof(*buf) + buflen);
97d8b01
+	if (!buf) {
97d8b01
+		err = ENOMEM;
97d8b01
+		goto err;
97d8b01
+	}
97d8b01
+
97d8b01
+	localgroup = conf_get_str("Static", (char *)name);
97d8b01
+	if (!localgroup) {
97d8b01
+		err = ENOENT;
97d8b01
+		goto err_free_buf;
97d8b01
+	}
97d8b01
+
97d8b01
+again:
97d8b01
+	err = getgrnam_r(localgroup, &buf->grbuf, buf->buf, buflen, &gr);
97d8b01
+
97d8b01
+	if (err == EINTR)
97d8b01
+		goto again;
97d8b01
+
97d8b01
+	if (!gr) {
97d8b01
+		if (err == 0)
97d8b01
+			err = ENOENT;
97d8b01
+
97d8b01
+		IDMAP_LOG(0, ("static_getgrnam: local group '%s' for '%s' not found\n",
97d8b01
+			  localgroup, name));
97d8b01
+
97d8b01
+		goto err_free_buf;
97d8b01
+	}
97d8b01
+
97d8b01
+	IDMAP_LOG(4, ("static_getgrnam: group '%s' mapped to '%s'\n",
97d8b01
+		  name, localgroup));
97d8b01
+
97d8b01
+	*err_p = 0;
97d8b01
+	return gr;
97d8b01
+
97d8b01
+err_free_buf:
97d8b01
+	free(buf);
97d8b01
+err:
97d8b01
+	*err_p = err;
97d8b01
+	return NULL;
97d8b01
+}
97d8b01
+
97d8b01
 static int static_gss_princ_to_ids(char *secname, char *princ,
97d8b01
 				   uid_t *uid, uid_t *gid,
97d8b01
 				   extra_mapping_params **ex)
97d8b01
@@ -151,14 +236,173 @@ static int static_gss_princ_to_grouplist(char *secname, char *princ,
97d8b01
 	return -err;
97d8b01
 }
97d8b01
 
97d8b01
+static int static_name_to_uid(char *name, uid_t *uid)
97d8b01
+{
97d8b01
+	struct passwd *pw;
97d8b01
+	int err;
97d8b01
+
97d8b01
+	pw = static_getpwnam(name, NULL, &err;;
97d8b01
+
97d8b01
+	if (pw) {
97d8b01
+		*uid = pw->pw_uid;
97d8b01
+		free(pw);
97d8b01
+	}
97d8b01
+
97d8b01
+	return -err;
97d8b01
+}
97d8b01
+
97d8b01
+static int static_name_to_gid(char *name, gid_t *gid)
97d8b01
+{
97d8b01
+	struct group *gr;
97d8b01
+	int err;
97d8b01
+
97d8b01
+	gr = static_getgrnam(name, NULL, &err;;
97d8b01
+
97d8b01
+	if (gr) {
97d8b01
+		*gid = gr->gr_gid;
97d8b01
+		free(gr);
97d8b01
+	}
97d8b01
+
97d8b01
+	return -err;
97d8b01
+}
97d8b01
+
97d8b01
+static int static_uid_to_name(uid_t uid, char *domain, char *name, size_t len)
97d8b01
+{
97d8b01
+	struct passwd *pw;
97d8b01
+	struct uid_mapping * um;
97d8b01
+
97d8b01
+	for (um = LIST_FIRST (&uid_mappings[uid_hash (uid)]); um;
97d8b01
+		um = LIST_NEXT (um, link)) {
97d8b01
+		if (um->uid == uid) {
97d8b01
+			strcpy(name, um->principal);
97d8b01
+			return 0;
97d8b01
+		}
97d8b01
+	}
97d8b01
+
97d8b01
+	return -ENOENT;
97d8b01
+}
97d8b01
+
97d8b01
+static int static_gid_to_name(gid_t gid, char *domain, char *name, size_t len)
97d8b01
+{
97d8b01
+	struct group *gr;
97d8b01
+	struct gid_mapping * gm;
97d8b01
+
97d8b01
+	for (gm = LIST_FIRST (&gid_mappings[gid_hash (gid)]); gm;
97d8b01
+		gm = LIST_NEXT (gm, link)) {
97d8b01
+		if (gm->gid == gid) {
97d8b01
+			strcpy(name, gm->principal);
97d8b01
+			return 0;
97d8b01
+		}
97d8b01
+	}
97d8b01
+
97d8b01
+	return -ENOENT;
97d8b01
+}
97d8b01
+
97d8b01
+/*
97d8b01
+ * We buffer all UID's for which static mappings is defined in advance, so the
97d8b01
+ * uid_to_name functions will be fast enough.
97d8b01
+ */
97d8b01
+
97d8b01
+static int static_init() {	
97d8b01
+	int err;
97d8b01
+	uid_t uid;
97d8b01
+	struct conf_list * princ_list = NULL;
97d8b01
+	struct conf_list_node * cln, *next;
97d8b01
+	struct uid_mapping * unode;
97d8b01
+	struct gid_mapping * gnode;
97d8b01
+	struct passwd * pw = NULL;
97d8b01
+	struct group * gr = NULL;
97d8b01
+	unsigned int i;
97d8b01
+
97d8b01
+	//init hash_table first
97d8b01
+	for (i = 0; i < sizeof uid_mappings / sizeof uid_mappings[0]; i++)
97d8b01
+		LIST_INIT (&uid_mappings[i]);
97d8b01
+
97d8b01
+	//get all principals for which we have mappings
97d8b01
+	princ_list = conf_get_tag_list("Static");
97d8b01
+
97d8b01
+	if (!princ_list) {
97d8b01
+		return -ENOENT;
97d8b01
+	}
97d8b01
+
97d8b01
+	/* As we can not distinguish between mappings for users and groups, we try to
97d8b01
+	 * resolve all mappings for both cases.
97d8b01
+	 */
97d8b01
+
97d8b01
+	//resolve uid of localname account for all such principals and cache it
97d8b01
+	for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) 
97d8b01
+	{ 
97d8b01
+		next = TAILQ_NEXT (cln, link); 
97d8b01
+
97d8b01
+		pw = static_getpwnam(cln->field, NULL, &err;;
97d8b01
+		if (!pw) {
97d8b01
+			continue;
97d8b01
+		}
97d8b01
+		
97d8b01
+		unode = calloc (1, sizeof *unode);
97d8b01
+		if (!unode)
97d8b01
+		{
97d8b01
+			warnx("static_init: calloc (1, %lu) failed",
97d8b01
+				(unsigned long)sizeof *unode);
97d8b01
+			free(pw);
97d8b01
+			return -ENOMEM;
97d8b01
+		}
97d8b01
+		unode->uid = pw->pw_uid;
97d8b01
+		unode->principal = strdup(cln->field);
97d8b01
+
97d8b01
+		unode->localname = conf_get_str("Static", cln->field);
97d8b01
+		if (!unode->localname) {
97d8b01
+			free(pw);
97d8b01
+			return -ENOENT;
97d8b01
+		}
97d8b01
+
97d8b01
+		free(pw);
97d8b01
+
97d8b01
+		LIST_INSERT_HEAD (&uid_mappings[uid_hash(unode->uid)], unode, link);
97d8b01
+	}
97d8b01
+
97d8b01
+	//resolve gid of localgroup accounts and cache it
97d8b01
+	for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) 
97d8b01
+	{ 
97d8b01
+		next = TAILQ_NEXT (cln, link); 
97d8b01
+
97d8b01
+		gr = static_getgrnam(cln->field, NULL, &err;;
97d8b01
+		if (!pw) {
97d8b01
+			continue;
97d8b01
+		}
97d8b01
+		
97d8b01
+		gnode = calloc (1, sizeof *gnode);
97d8b01
+		if (!gnode)
97d8b01
+		{
97d8b01
+			warnx("static_init: calloc (1, %lu) failed",
97d8b01
+				(unsigned long)sizeof *gnode);
97d8b01
+			free(pw);
97d8b01
+			return -ENOMEM;
97d8b01
+		}
97d8b01
+		gnode->gid = pw->pw_uid;
97d8b01
+		gnode->principal = strdup(cln->field);
97d8b01
+
97d8b01
+		gnode->localgroup = conf_get_str("Static", cln->field);
97d8b01
+		if (!gnode->localgroup) {
97d8b01
+			free(pw);
97d8b01
+			return -ENOENT;
97d8b01
+		}
97d8b01
+
97d8b01
+		free(pw);
97d8b01
+
97d8b01
+		LIST_INSERT_HEAD (&gid_mappings[gid_hash(gnode->gid)], gnode, link);
97d8b01
+	}
97d8b01
+	return 0;
97d8b01
+}
97d8b01
+
97d8b01
 
97d8b01
 struct trans_func static_trans = {
97d8b01
 	.name			= "static",
97d8b01
-	.init			= NULL,
97d8b01
-	.name_to_uid		= NULL,
97d8b01
-	.name_to_gid		= NULL,
97d8b01
-	.uid_to_name		= NULL,
97d8b01
-	.gid_to_name		= NULL,
97d8b01
+	.init			= static_init,
97d8b01
+	.name_to_uid		= static_name_to_uid,
97d8b01
+	.name_to_gid		= static_name_to_gid,
97d8b01
+	.uid_to_name		= static_uid_to_name,
97d8b01
+	.gid_to_name		= static_gid_to_name,
97d8b01
 	.princ_to_ids		= static_gss_princ_to_ids,
97d8b01
 	.gss_princ_to_grouplist	= static_gss_princ_to_grouplist,
97d8b01
 };
97d8b01
diff --git a/umich_ldap.c b/umich_ldap.c
97d8b01
index f482b0a..b527c5d 100644
97d8b01
--- a/umich_ldap.c
97d8b01
+++ b/umich_ldap.c
97d8b01
@@ -32,8 +32,6 @@
97d8b01
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97d8b01
  */
97d8b01
 
97d8b01
-#ifdef ENABLE_LDAP
97d8b01
-
97d8b01
 #include <sys/types.h>
97d8b01
 #include <sys/socket.h>
97d8b01
 #include <netdb.h>
97d8b01
@@ -1302,4 +1300,3 @@ struct trans_func *libnfsidmap_plugin_init()
97d8b01
 {
97d8b01
 	return (&umichldap_trans);
97d8b01
 }
97d8b01
-#endif