--- old/usr/src/cmd/ypcmd/revnetgroup/Makefile	Tue Sep 11 18:26:14 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/Makefile	Tue Sep 11 18:26:13 2012
@@ -23,7 +23,7 @@
 # Copyright 1996, 2002 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
 #
 
 PROG = revnetgroup
@@ -32,14 +32,19 @@
 
 OBJS = revnetgroup.o getgroup.o table.o util.o
 SRCS = $(OBJS:.o=.c)
-HDRS = getgroup.h table.h util.h
+HDRS = getgroup.h table.h util.h revnetgroup.h
 
+OBJS_PROG = main.o
+SRCS_PROG = $(OBJS_PROG:.o=.c)
+
 .KEEP_STATE:
 
 all: $(PROG)
 
-$(PROG): $(OBJS)
-	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+LDLIBS +=	-lrevnetgroup
+
+$(PROG): $(OBJS_PROG) $(HDRS)
+	$(LINK.c) $(OBJS_PROG) -o $@ $(LDLIBS)
 	$(POST_PROCESS)
 
 install: all $(ROOTUSRSBINPROG)
--- old/usr/src/cmd/ypcmd/revnetgroup/getgroup.c	Tue Sep 11 18:26:14 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/getgroup.c	Tue Sep 11 18:26:14 2012
@@ -23,10 +23,11 @@
 /*
  * Copyright (c) 1996, by Sun Microsystems, Inc.
  * All rights reserved.
+ *
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
-							    
-#ident	"%Z%%M%	%I%	%E% SMI"	/* SMI4.1 1.5 */
 
+#include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <string.h>
@@ -34,8 +35,6 @@
 #include "util.h"
 #include "getgroup.h"
 
-#define	MAXGROUPLEN 1024
-
 /*
  * Stolen mostly, from getnetgrent.c
  *
@@ -53,57 +52,35 @@
 	struct list *nxt;
 };
 
-
-extern stringtable ngtable; /* stored info from /etc/netgroup */
-
-static struct grouplist *grouplist; /* stores a list of users in a group */
-
 static char *any();
 static char *match();
 static char *fill();
-static void freegrouplist();
-static void doit();
 
 
-
-static void
-freegrouplist()
+void
+freegrouplist(revhandle_t *hdl)
 {
-	struct grouplist *gl;
+	struct grouplist *gl, *next;
 
-	for (gl = grouplist; gl != NULL; gl = gl->gl_nxt) {
+	for (gl = hdl->grouplist; gl != NULL; gl = next) {
+		next = gl->gl_nxt;
+
 		FREE(gl->gl_name);
 		FREE(gl->gl_domain);
 		FREE(gl->gl_machine);
 		FREE(gl);
 	}
-	grouplist = NULL;
+	hdl->grouplist = NULL;
 }
 
 
 
-
-struct grouplist *
-my_getgroup(group)
-	char *group;
-{
-	freegrouplist();
-	doit(group, (struct list *) NULL);
-	return (grouplist);
-}
-
-
-
-
-
 /*
  * recursive function to find the members of netgroup "group". "list" is
  * the path followed through the netgroups so far, to check for cycles.
  */
-static void
-doit(group, list)
-	char *group;
-	struct list *list;
+void
+doit(char *group, struct list *list, revhandle_t *hdl)
 {
 	register char *p, *q;
 	register struct list *ls;
@@ -115,7 +92,7 @@
 	/*
 	 * check for non-existing groups
 	 */
-	if ((val = match(group)) == NULL) {
+	if ((val = match(group, hdl)) == NULL) {
 		return;
 	}
 
@@ -126,8 +103,8 @@
 	for (ls = list; ls != NULL; ls = ls->nxt) {
 		if (strcmp(ls->name, group) == 0) {
 			(void) fprintf(stderr,
-				"Cycle detected in /etc/netgroup: %s.\n",
-				group);
+			    "Cycle detected in /etc/netgroup: %s.\n",
+			    group);
 			return;
 		}
 	}
@@ -157,14 +134,14 @@
 			if (!(p = fill(p, &gpls->gl_domain, ')'))) {
 				goto syntax_error;
 			}
-			gpls->gl_nxt = grouplist;
-			grouplist = gpls;
+			gpls->gl_nxt = hdl->grouplist;
+			hdl->grouplist = gpls;
 		} else {
 			q = any(p, " \t\n#");
 			if (q && *q == '#')
 				break;
 			*q = EOS;
-			doit(p, list);
+			doit(p, list, hdl);
 			*q = ' ';
 		}
 		p = any(p, " \t");
@@ -242,8 +219,7 @@
  * The equivalent of yp_match. Returns the match, or NULL if there is none.
  */
 static char *
-match(group)
-	char *group;
+match(char *group, revhandle_t *hdl)
 {
-	return (lookup(ngtable, group));
+	return (lookup(hdl->ngtable, group));
 }
--- old/usr/src/cmd/ypcmd/revnetgroup/getgroup.h	Tue Sep 11 18:26:15 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/getgroup.h	Tue Sep 11 18:26:15 2012
@@ -22,19 +22,18 @@
 /*
  * Copyright 1995 Sun Microsystems Inc.
  * All rights reserved.
+ *
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
-							    
 
 #ifndef	__GETGROUP_H
 #define	__GETGROUP_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"        /* SMI4.1 1.4 */
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-struct grouplist {		
+struct grouplist {
 	char *gl_machine;
 	char *gl_name;
 	char *gl_domain;
@@ -41,7 +40,9 @@
 	struct grouplist *gl_nxt;
 };
 
-struct grouplist *my_getgroup();
+struct list;
+void freegrouplist(revhandle_t *);
+void doit(char *group, struct list *list, revhandle_t *hdl);
 
 #ifdef	__cplusplus
 }
--- /dev/null	Mon Sep 10 13:31:06 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/main.c	Tue Sep 11 18:26:16 2012
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "revnetgroup.h"
+
+int
+main(int argc, char *argv[])
+{
+	int byuser;
+
+	if (argc == 2 && argv[1][0] == '-' &&
+	    (argv[1][1] == 'u' || argv[1][1] == 'h')) {
+		byuser = (argv[1][1] == 'u');
+	} else {
+		(void) fprintf(stderr,
+		    "usage: %s -h (by host), %s -u (by user)\n",
+		    argv[0], argv[0]);
+		exit(1);
+	}
+
+	revnetgroup_handle(stdin, stdout, byuser);
+	return (0);
+}
--- old/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c	Tue Sep 11 18:26:17 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c	Tue Sep 11 18:26:16 2012
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -37,9 +38,11 @@
 #include "util.h"
 #include "table.h"
 #include "getgroup.h"
+#include "revnetgroup.h"
 
 #define	MAXDOMAINLEN 256
-#define	MAXGROUPLEN 1024
+#define	MAXGROUPLEN  131072
+#define	MAXKEYLEN    512
 
 /*
  * Reverse the netgroup file. A flag of "-u" means reverse by username,
@@ -58,65 +61,30 @@
  *
  */
 
-
-
-/* Stores a list of strings */
-typedef struct stringnode *stringlist;
-struct stringnode {
-    char *str;
-    stringlist next;
-};
-typedef struct stringnode stringnode;
-
-
-
-/* Stores a list of (name,list-of-groups) */
-typedef struct groupentrynode *groupentrylist;
-struct groupentrynode {
-    char *name;
-    stringlist groups;
-    groupentrylist next;
-};
-typedef struct groupentrynode groupentrynode;
-
-stringtable ngtable;
-
-static groupentrylist grouptable[TABLESIZE];
-
-static char *nextgroup(void);
-static void storegroup(char *group, struct grouplist *glist, int byuser);
-static void enter(char *name, char *group);
+static char *nextgroup(revhandle_t *, tablelist *);
+static void storegroup(char *group, revhandle_t *hdl);
+static void enter(char *name, char *group, revhandle_t *hdl);
 static void appendgroup(groupentrylist grlist, char *group);
 static groupentrylist newentry(char *name, char *group);
-static void loadtable(FILE *nf);
-static void dumptable(void);
+static void loadtable(FILE *nf, revhandle_t *hdl);
+static void dumptable(FILE *out, revhandle_t *hdl);
+static void free_table(revhandle_t *hdl);
 
 int
-main(argc, argv)
-    int argc;
-    char *argv[];
+revnetgroup_handle(FILE *fin, FILE *fout, boolean_t byuser)
 {
 	char *group;
-	struct grouplist *glist;
-	int byuser;
+	revhandle_t hdl = {0};
+	tablelist walker = NULL;
 
-	loadtable(stdin);
-	if (argc == 2 && argv[1][0] == '-' &&
-			(argv[1][1] == 'u' || argv[1][1] == 'h')) {
-		byuser = (argv[1][1] == 'u');
-	} else {
-		(void) fprintf(stderr,
-				"usage: %s -h (by host), %s -u (by user)\n",
-				argv[0], argv[0]);
-		exit(1);
-	}
+	hdl.rh_byuser = byuser;
+	loadtable(fin, &hdl);
 
-	while (group = nextgroup()) {
-		glist = my_getgroup(group);
-		storegroup(group, glist, byuser);
-	}
-	dumptable();
+	while (group = nextgroup(&hdl, &walker))
+		storegroup(group, &hdl);
 
+	dumptable(fout, &hdl);
+	free_table(&hdl);
 	return (0);
 }
 
@@ -124,48 +92,123 @@
  *	Get the next netgroup from /etc/netgroup
  */
 static char *
-nextgroup(void)
+nextgroup(revhandle_t *hdl, tablelist *next)
 {
-	static int index = -1;
-	static tablelist cur = NULL;
-	char *group;
+	tablelist entry = *next;
+	uint_t i;
 
-	while (cur == NULL) {
-		if (++index == TABLESIZE) {
-			return (NULL);
+	if (entry == NULL) {
+		for (i = hdl->rh_index; i < TABLESIZE; i++) {
+			entry = hdl->ngtable[i];
+			if (entry != NULL) {
+				hdl->rh_index = i + 1;
+				break;
+			}
 		}
-		cur = ngtable[index];
 	}
-	group = cur->key;
-	cur = cur->next;
-	return (group);
+
+	if (entry == NULL) {
+		/* out of table */
+		hdl->rh_index = 0;
+		return (NULL);
+	}
+
+	*next = entry->next;
+	return (entry->key);
 }
 
 
+static void
+free_tablelist(tablelist e)
+{
+	tablelist next;
 
+	do {
+		next = e->next;
+
+		free(e->key);
+		free(e->datum);
+		free(e);
+	} while ((e = next) != NULL);
+}
+
+static void
+free_stringnode(stringnode *s)
+{
+	stringnode *next;
+
+	do {
+		next = s->s_next;
+
+		free(s);
+	} while ((s = next) != NULL);
+}
+
+static void
+free_groupentrylist(groupentrylist e)
+{
+	groupentrylist next;
+
+	do {
+		next = e->next;
+
+		free_stringnode(e->groups);
+		free(e->name);
+		free(e);
+	} while ((e = next) != NULL);
+}
+
+static void
+free_table(revhandle_t *hdl)
+{
+	int i;
+
+	/* ngtable */
+	for (i = 0; i < TABLESIZE; i++) {
+		tablelist e;
+
+		if ((e = hdl->ngtable[i]) == NULL)
+			continue;
+
+		free_tablelist(e);
+		hdl->ngtable[i] = NULL;
+	}
+
+	/* grouptable */
+	for (i = 0; i < TABLESIZE; i++) {
+		groupentrylist e;
+
+		if ((e = hdl->grouptable[i]) == NULL)
+			continue;
+
+		free_groupentrylist(e);
+		hdl->grouptable[i] = NULL;
+	}
+}
+
 /*
  * Dump out all of the stored info into a file
  */
 static void
-dumptable(void)
+dumptable(FILE *out, revhandle_t *hdl)
 {
 	int i;
 	groupentrylist entry;
-	stringlist groups;
+	stringnode *groups;
 
 	for (i = 0; i < TABLESIZE; i++) {
-		if (entry = grouptable[i]) {
+		if (entry = hdl->grouptable[i]) {
 			while (entry) {
-				fputs(entry->name, stdout);
-				putc('\t', stdout);
+				fputs(entry->name, out);
+				putc('\t', out);
 				for (groups = entry->groups; groups;
-						groups = groups->next) {
-					fputs(groups->str, stdout);
-					if (groups->next) {
-						putc(',', stdout);
+				    groups = groups->s_next) {
+					fputs(groups->str, out);
+					if (groups->s_next) {
+						putc(',', out);
 					}
 				}
-				putc('\n', stdout);
+				putc('\n', out);
 				entry = entry->next;
 			}
 		}
@@ -174,33 +217,35 @@
 
 
 
-
 /*
  *	Add a netgroup to a user's list of netgroups
  */
 static void
-storegroup(char *group, struct grouplist *glist, int byuser)
+storegroup(char *group, revhandle_t *hdl)
 {
-	char *name;	/* username or hostname */
-	char *domain;
-	char *key;
-	static char *universal = "*";
+	char key[MAXKEYLEN];
+	struct grouplist *glist;
 
-	for (; glist; glist = glist->gl_nxt) {
-		name = byuser ? glist->gl_name : glist->gl_machine;
+	doit(group, (struct list *)NULL, hdl);
+
+	for (glist = hdl->grouplist; glist; glist = glist->gl_nxt) {
+		const char *name;	/* username or hostname */
+		const char *domain;
+
+		name = hdl->rh_byuser ? glist->gl_name : glist->gl_machine;
 		if (!name) {
-		    name = universal;
+			name = "*";
 		} else if (!isalnum(*name) && *name != '_') {
-		    continue;
+			continue;
 		}
 		domain = glist->gl_domain;
 		if (!domain) {
-		    domain = universal;
+			domain = "*";
 		}
-		key = malloc((unsigned) (strlen(name)+strlen(domain)+2));
-		(void) sprintf(key, "%s.%s", name, domain);
-		enter(key, group);
+		(void) snprintf(key, sizeof (key), "%s.%s", name, domain);
+		enter(key, group, hdl);
 	}
+	freegrouplist(hdl);
 }
 
 
@@ -216,7 +261,7 @@
 
 	new->groups = MALLOC(stringnode);
 	new->groups->str = group;
-	new->groups->next = NULL;
+	new->groups->s_next = NULL;
 
 	new->next = NULL;
 	return (new);
@@ -225,21 +270,21 @@
 static void
 appendgroup(groupentrylist grlist, char *group)
 {
-	stringlist cur, prev;
+	stringnode *cur, *prev;
 
-	for (cur = grlist->groups; cur; prev = cur, cur = cur->next) {
+	for (cur = grlist->groups; cur; prev = cur, cur = cur->s_next) {
 		if (strcmp(group, cur->str) == 0) {
-		    return;
+			return;
 		}
 	}
-	prev->next = MALLOC(stringnode);
-	cur = prev->next;
+	prev->s_next = MALLOC(stringnode);
+	cur = prev->s_next;
 	cur->str = group;
-	cur->next = NULL;
+	cur->s_next = NULL;
 }
 
 static void
-enter(char *name, char *group)
+enter(char *name, char *group, revhandle_t *hdl)
 {
 	int key;
 	groupentrylist gel;
@@ -246,18 +291,18 @@
 	groupentrylist gelprev;
 
 	key = tablekey(name);
-	if (grouptable[key] == NULL) {
-		grouptable[key] = newentry(name, group);
+	if (hdl->grouptable[key] == NULL) {
+		hdl->grouptable[key] = newentry(name, group);
 	} else {
-		gel = grouptable[key];
+		gel = hdl->grouptable[key];
 		while (gel && strcmp(gel->name, name)) {
-		    gelprev = gel;
-		    gel = gel->next;
+			gelprev = gel;
+			gel = gel->next;
 		}
 		if (gel) {
-		    appendgroup(gel, group);
+			appendgroup(gel, group);
 		} else {
-		    gelprev->next = newentry(name, group);
+			gelprev->next = newentry(name, group);
 		}
 	}
 }
@@ -266,16 +311,21 @@
  * Load up a hash table with the info in /etc/netgroup
  */
 static void
-loadtable(FILE *nf)
+loadtable(FILE *nf, revhandle_t *hdl)
 {
-	char buf[MAXGROUPLEN];
+	char *buf;
 	char *p;
 	char *group;
 	char *line;
 
+	buf = malloc(MAXGROUPLEN);
+	if (buf == NULL)
+		return;
+
 	while (getaline(buf, MAXGROUPLEN, nf)) {
+		/* skip leading blanks */
 		for (p = buf; *p && isspace((int)*p); p++)
-			;	/* skip leading blanks */
+			;
 		for (; *p && *p != '#' && *p != ' ' && *p != '\t'; p++)
 			;
 		if (*p == EOS || *p == '#')
@@ -290,6 +340,8 @@
 
 		STRCPY(group, buf);
 		STRCPY(line, p);
-		store(ngtable, group, line);
+		store(hdl->ngtable, group, line);
 	}
+
+	free(buf);
 }
--- /dev/null	Mon Sep 10 13:31:08 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.h	Tue Sep 11 18:26:17 2012
@@ -0,0 +1,31 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#ifndef	_REVNETGROUP_H
+#define	_REVNETGROUP_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+extern int revnetgroup_handle(FILE *fin, FILE *fout, boolean_t byuser);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _REVNETGROUP_H */
--- old/usr/src/cmd/ypcmd/revnetgroup/table.c	Tue Sep 11 18:26:19 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/table.c	Tue Sep 11 18:26:18 2012
@@ -22,10 +22,12 @@
 /*
  * Copyright (c) 1994, by Sun Microsystems, Inc.
  * All rights reserved.
+ *
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
-							    
-#ident	"%Z%%M%	%I%	%E% SMI"	/* SMI4.1 1.4 */
 
+#include <stdlib.h>
+#include <strings.h>
 #include <ctype.h>
 #include "util.h"
 #include "table.h"
@@ -63,7 +65,7 @@
 
 void
 store(table, key, datum)
-	stringtable table;
+	tablelist *table;
 	char *key;
 	char *datum;
 {
@@ -83,7 +85,7 @@
 
 char *
 lookup(table, key)
-	stringtable table;
+	tablelist *table;
 	char *key;
 {
 	tablelist cur;
--- old/usr/src/cmd/ypcmd/revnetgroup/table.h	Tue Sep 11 18:26:20 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/table.h	Tue Sep 11 18:26:19 2012
@@ -22,31 +22,52 @@
 /*
  * Copyright 1995 Sun Microsystems Inc.
  * All rights reserved.
+ *
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
-							    
 
 #ifndef	__TABLE_H
 #define	__TABLE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"        /* SMI4.1 1.4 */
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#define NUMLETTERS 27 /* 26 letters  + 1 for anything else */
-#define TABLESIZE (NUMLETTERS*NUMLETTERS)
+#include <sys/types.h>
 
+#define	NUMLETTERS 27 /* 26 letters  + 1 for anything else */
+#define	TABLESIZE (NUMLETTERS*NUMLETTERS)
+
 typedef struct tablenode *tablelist;
-struct tablenode {
+typedef struct tablenode {
 	char *key;
 	char *datum;
 	tablelist next;
-};
-typedef struct tablenode tablenode;
+} tablenode;
 
-typedef tablelist stringtable[TABLESIZE];
+/* Stores a list of strings */
+typedef struct stringnode {
+	char *str;
+	struct stringnode *s_next;
+} stringnode;
 
+/* Stores a list of (name,list-of-groups) */
+typedef struct groupentrynode *groupentrylist;
+
+typedef struct groupentrynode {
+	char *name;
+	stringnode *groups;
+	groupentrylist next;
+} groupentrynode;
+
+typedef struct revhandle {
+	tablelist	ngtable[TABLESIZE];
+	groupentrylist	grouptable[TABLESIZE];
+	struct grouplist *grouplist;   /* stores a list of users in a group */
+	uint_t		rh_index;
+	boolean_t	rh_byuser;
+} revhandle_t;
+
 int tablekey();
 char *lookup();
 void store();
--- old/usr/src/cmd/ypcmd/revnetgroup/util.c	Tue Sep 11 18:26:21 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/util.c	Tue Sep 11 18:26:20 2012
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <stdio.h>
@@ -97,13 +98,4 @@
 	(void) fprintf(stderr, "Following line too long - remaining chars "
 			"ignored\n--- %s", line);
 	return (line);
-}
-
-
-void
-fatal(message)
-	char *message;
-{
-	(void) fprintf(stderr, "fatal error: %s\n", message);
-	exit(1);
 }
--- old/usr/src/cmd/ypcmd/revnetgroup/util.h	Tue Sep 11 18:26:22 2012
+++ new/usr/src/cmd/ypcmd/revnetgroup/util.h	Tue Sep 11 18:26:21 2012
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef	__UTIL_H
@@ -30,31 +31,20 @@
 extern "C" {
 #endif
 
-#define EOS '\0'
+#define	EOS '\0'
 
-#ifndef NULL 
-#	define NULL ((char *) 0)
-#endif
+#define	MALLOC(object_type) ((object_type *)malloc(sizeof (object_type)))
 
+#define	FREE(ptr)	free((char *)ptr)
 
-#define MALLOC(object_type) ((object_type *) malloc(sizeof(object_type)))
+#define	STRCPY(dst, src) \
+	(dst = malloc((unsigned)strlen(src)+1), (void)strcpy(dst, src))
 
-#define FREE(ptr)	free((char *) ptr) 
+#define	STRNCPY(dst, src, num) \
+	(dst = (char *)malloc((unsigned)(num) + 1),\
+	(void) strncpy(dst, src, num), (dst)[num] = EOS)
 
-#define STRCPY(dst,src) \
-	(dst = malloc((unsigned)strlen(src)+1), (void) strcpy(dst,src))
-
-#define STRNCPY(dst,src,num) \
-	(dst = (char *) malloc((unsigned)(num) + 1),\
-	(void)strncpy(dst,src,num),(dst)[num] = EOS) 
-
-/*
-extern char *malloc();
-*/
-extern char *alloca();
-
 char *getaline();
-void fatal();
 
 #ifdef	__cplusplus
 }
--- /dev/null	Mon Sep 10 13:31:12 2012
+++ new/usr/src/lib/librevnetgroup/Makefile	Tue Sep 11 18:26:22 2012
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+#
+
+# include library definitions
+include ../Makefile.lib
+
+HDRS = revnetgroup.h
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FORCE
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FORCE:
+
+install_h:
+	cp $(SRC)/cmd/ypcmd/revnetgroup/$(HDRS) $(ROOTHDRS)
+
+include ../Makefile.targ
--- /dev/null	Mon Sep 10 13:31:13 2012
+++ new/usr/src/lib/librevnetgroup/Makefile.com	Tue Sep 11 18:26:23 2012
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+#
+
+LIBRARY=	librevnetgroup.a
+VERS=		.1
+OBJECTS=	revnetgroup.o getgroup.o table.o util.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+COMDIR =	$(SRC)/cmd/ypcmd/revnetgroup
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+SRCS =		$(COMDIR)/*.c
+
+LDLIBS +=	-lc
+
+$(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all : $(LIBS)
+
+lint: lintcheck
+
+pics/%.o:	 $(COMDIR)/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
+
+
+include ../../Makefile.targ
--- /dev/null	Mon Sep 10 13:31:14 2012
+++ new/usr/src/lib/librevnetgroup/amd64/Makefile	Tue Sep 11 18:26:24 2012
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Mon Sep 10 13:31:14 2012
+++ new/usr/src/lib/librevnetgroup/i386/Makefile	Tue Sep 11 18:26:24 2012
@@ -0,0 +1,17 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Mon Sep 10 13:31:15 2012
+++ new/usr/src/lib/librevnetgroup/llib-lrevnetgroup	Tue Sep 11 18:26:25 2012
@@ -0,0 +1,18 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+ /*
+  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+  */
+#include <stdio.h>
+#include <revnetgroup.h>
--- /dev/null	Mon Sep 10 13:31:16 2012
+++ new/usr/src/lib/librevnetgroup/mapfile-vers	Tue Sep 11 18:26:26 2012
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+#
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+#
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.1 {
+    global:
+	revnetgroup_handle;
+    local:
+	*;
+};
--- old/usr/src/lib/nsswitch/files/Makefile.com	Tue Sep 11 18:26:27 2012
+++ new/usr/src/lib/nsswitch/files/Makefile.com	Tue Sep 11 18:26:27 2012
@@ -22,7 +22,7 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
 #
 
 LIBRARY =	libnss_files.a
@@ -32,6 +32,7 @@
 		ether_addr.o		\
 		files_common.o		\
 		getgrent.o		\
+		getnetgrent.o		\
 		gethostent.o		\
 		gethostent6.o		\
 		getnetent.o		\
@@ -61,7 +62,7 @@
 LINTFLAGS +=	-erroff=E_GLOBAL_COULD_BE_STATIC2
 LINTFLAGS64 +=	-erroff=E_GLOBAL_COULD_BE_STATIC2 
 
-LDLIBS +=	-lsocket -lnsl
+LDLIBS +=	-lsocket -lnsl -lrevnetgroup
 DYNLIB1 =	nss_files.so$(VERS)
 
 all: $(DYNLIB1)
--- /dev/null	Mon Sep 10 13:31:18 2012
+++ new/usr/src/lib/nsswitch/files/common/getnetgrent.c	Tue Sep 11 18:26:28 2012
@@ -0,0 +1,311 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <thread.h>
+#include <synch.h>
+#include <time.h>
+#include <revnetgroup.h>
+
+#include "files_common.h"
+
+#define	PATH_NETGROUP		"/etc/netgroup"
+
+static uint_t
+hash_netgr_host(nss_XbyY_args_t *argp, int keyhash, const char *line,
+	int linelen)
+{
+	const char *end;
+	uint_t hash = 0;
+	int power = 0;
+
+	if (keyhash) {
+		struct nss_innetgr_args	*ia;
+
+		ia = (struct nss_innetgr_args *)argp->key.name;
+
+		line = ia->arg[NSS_NETGR_MACHINE].argv[0];
+		end = line + strlen(line);
+	} else {
+		const char *s;
+
+		end = strchr(line, '\t');
+		if (end == NULL)
+			end = line;
+
+		s = strstr(line, ".*");
+		if (s != NULL && s < end) {
+			end = s;
+		}
+
+	}
+
+	while (line < end) {
+		uint_t c = *line++;
+
+		c <<= power++;
+		hash += c;
+	}
+
+	return (hash);
+}
+
+static files_hash_func hash_netgr[] = { hash_netgr_host };
+
+static files_hash_t hashinfo = {
+	DEFAULTMUTEX,
+	0,
+	NSS_BUFLEN_GROUP,
+	1,
+	hash_netgr
+};
+
+/* ARGSUSED */
+static int
+dummy_netgr(const char *in, int inlen,
+    void *ent, char *buf, int buflen)
+{
+	return (NSS_STR_PARSE_SUCCESS);
+}
+
+/*
+ * return parsed or not
+ */
+static boolean_t
+netgr_extract_hostname(char *str, char **hostname, char **next)
+{
+	char *s;
+
+	s = strchr(str, '\t');
+	if (s == NULL || s == str)
+		return (B_FALSE);
+
+	*s = '\0';
+	*hostname = str;
+	*next = s + 1;
+
+	return (B_TRUE);
+}
+
+static boolean_t
+netgr_hosts_match(const char *hostname, const char *host, const char *domain)
+{
+	char buf[NSS_BUFSIZ];
+	uint_t n;
+
+	/*
+	 * hostname can be "a.b.c.*"
+	 */
+	n = strlen(hostname);
+	if (n > 0 && hostname[n - 1] == '*')
+		domain = "*";
+
+	snprintf(buf, sizeof (buf), "%s.%s", host, domain);
+
+	if (strcmp(hostname, buf))
+		return (B_FALSE);
+	else
+		return (B_TRUE);
+}
+
+static boolean_t
+netgr_netgroups_match(const char *netgroups, const char *group)
+{
+	char *s;
+	uint_t len;
+
+	/* walk netgroups */
+
+	s = strstr(netgroups, group);
+	if (s == NULL)
+		return (B_FALSE);
+
+	/* check beginning */
+	if (s != netgroups && s[-1] != ',')
+		return (B_FALSE);
+
+	/* check end */
+	len = strlen(group);
+	if (s[len] != ',' && s[len] != '\0')
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
+/*
+ * Parse string: "{hostname} {netgroup1} ... {netgroup2}"
+ */
+static int
+check_netgr(nss_XbyY_args_t *argp, const char *line, int linelen)
+{
+	struct nss_innetgr_args	*ia;
+	char buf[NSS_BUFSIZ];
+	const char *host;
+	const char *domain;
+	const char *group;
+	const char *netgroup;
+	char *hostname, *next;
+
+	if (linelen > NSS_BUFSIZ || linelen < 0)
+		return (0);
+
+	/* use only one passed argument */
+	ia = (struct nss_innetgr_args *)argp->key.name;
+	host = ia->arg[NSS_NETGR_MACHINE].argv[0];
+	domain = ia->arg[NSS_NETGR_DOMAIN].argv[0];
+	netgroup = ia->groups.argv[0];
+
+	strlcpy(buf, line, NSS_BUFSIZ);
+
+	if (!netgr_extract_hostname(buf, &hostname, &next))
+		return (0);
+
+	if (!netgr_hosts_match(hostname, host, domain))
+		return (0);
+
+	if (!netgr_netgroups_match(next, netgroup))
+		return (0);
+
+	return (1);
+}
+
+static nss_status_t
+netgr_in(files_backend_ptr_t be, void *a)
+{
+	struct nss_innetgr_args	*ia = (struct nss_innetgr_args *)a;
+	nss_status_t	rc = (nss_status_t)NSS_NOTFOUND;
+	nss_XbyY_args_t xa = {0};
+	struct stat64 st;
+	int retries;
+
+	retries = 5;
+	while (stat64(PATH_NETGROUP, &st) < 0) {
+		struct timespec delay;
+
+		/* 50 ms */
+		delay.tv_sec = 0;
+		delay.tv_nsec = 50000000;
+
+		nanosleep(&delay, NULL);
+		if (--retries == 0)
+			goto out;
+	}
+
+	mutex_lock(&hashinfo.fh_lock);
+
+	if ((uint_t)st.st_mtim.tv_sec > (uint_t)hashinfo.fh_mtime.tv_sec) {
+		FILE *fin, *fout;
+
+		/*
+		 * netgroup file is more recent than parsed copy
+		 */
+
+		fin = fopen(PATH_NETGROUP, "r");
+		if (fin == NULL)
+			goto out_unlock;
+
+		fout = fopen(be->filename, "w");
+		if (fout == NULL) {
+			fclose(fin);
+			goto out_unlock;
+		}
+
+		revnetgroup_handle(fin, fout, B_FALSE);
+
+		fclose(fout);
+		fclose(fin);
+	}
+
+out_unlock:
+	mutex_unlock(&hashinfo.fh_lock);
+
+	/* some hack to pass arguments to check_netgr */
+	xa.key.name = (char *)ia;
+	xa.str2ent = dummy_netgr;
+	rc = _nss_files_XY_hash(be, &xa, 1, &hashinfo, 0, check_netgr);
+
+out:
+	ia->status = (rc == NSS_SUCCESS) ? NSS_NETGR_FOUND : NSS_NETGR_NO;
+	return (rc);
+}
+
+/*ARGSUSED*/
+nss_status_t
+netgr_files_destr(files_backend_ptr_t be, void *dummy)
+{
+	nss_status_t status;
+
+	unlink(be->filename);
+	free((void *)be->filename);
+	status = _nss_files_destr(be, dummy);
+	return (status);
+}
+
+static char *
+create_uniq_filename(void)
+{
+	char *filename;
+	int dummy_fd;
+
+	filename = malloc(PATH_MAX);
+	if (filename == NULL)
+		return (NULL);
+
+	strlcpy(filename, "/tmp/revnetgroup-XXXXXX", PATH_MAX);
+
+	dummy_fd = mkstemp(filename);
+	close(dummy_fd);
+	if (dummy_fd < 0) {
+		free(filename);
+		return (NULL);
+	}
+	return (filename);
+}
+
+static files_backend_op_t netgr_ops[] = {
+	netgr_files_destr,
+	NULL,			/* No endent, because no setent */
+	NULL,			/* No setent */
+	NULL,			/* No getent_netdb */
+	netgr_in,		/* innetgr */
+	NULL,			/* No setnetgrent */
+};
+
+/*ARGSUSED*/
+nss_backend_t *
+_nss_files_netgroup_constr(const char *dummy1,
+    const char *dummy2, const char *dummy3)
+{
+	char *filename;
+
+	filename = create_uniq_filename();
+	if (filename == NULL)
+		return (NULL);
+
+	return (_nss_files_constr(netgr_ops,
+	    sizeof (netgr_ops) / sizeof (netgr_ops[0]),
+	    filename,
+	    NSS_LINELEN_NETWORKS,
+	    NULL));
+}
--- old/usr/src/lib/nsswitch/files/common/mapfile-vers	Tue Sep 11 18:26:29 2012
+++ new/usr/src/lib/nsswitch/files/common/mapfile-vers	Tue Sep 11 18:26:28 2012
@@ -1,5 +1,6 @@
 #
 # Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
 #
 # CDDL HEADER START
 #
@@ -65,6 +66,7 @@
 		_nss_files_user_attr_constr;
 		_nss_files_tnrhdb_constr;
 		_nss_files_tnrhtp_constr;
+		_nss_files_netgroup_constr;
 	local:
 		*;
 };
