Subject: id(1) flag to get group members
To: None <tech-userlevel@netbsd.org>
From: Jan Schaumann <jschauma@netmeister.org>
List: tech-userlevel
Date: 06/17/2006 18:38:03
--8vCeF2GUdMpe9ZbK
Content-Type: multipart/mixed; boundary="tEFtbjk+mNEviIIX"
Content-Disposition: inline


--tEFtbjk+mNEviIIX
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi,

I've on occasion had the need for a tool that tells me the users in a
given group.  Sure, I could manually look at /etc/group or the NIS
database, but it seemed to me like id(1) should be able to do that.

The attached patch provides a flag for id(1) to get a groups members.
(This only lists users who are in the supplementary group, not where the
group is the primary group of a user.)

Does this make sense?

-Jan

--=20
Free Speech Online - Stop Internet Censorship
   --- Electronic Frontier Foundation -- http://www.eff.org ---

--tEFtbjk+mNEviIIX
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="id.diff"
Content-Transfer-Encoding: quoted-printable

Index: id.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/usr.bin/id/id.1,v
retrieving revision 1.12
diff -b -u -r1.12 id.1
--- id.1	19 Nov 2004 14:18:01 -0000	1.12
+++ id.1	17 Jun 2006 22:18:45 -0000
@@ -32,7 +32,7 @@
 .\"
 .\"	@(#)id.1	8.2 (Berkeley) 5/5/94
 .\"
-.Dd May 5, 1994
+.Dd June 12, 2006
 .Dt ID 1
 .Os
 .Sh NAME
@@ -51,6 +51,9 @@
 .Fl p
 .Op Ar user
 .Nm
+.Fl s Op Fl n
+.Ar group
+.Nm
 .Fl u Op Fl nr
 .Op Ar user
 .Sh DESCRIPTION
@@ -105,6 +108,11 @@
 and
 .Fl u
 options instead of the effective ID.
+.It Fl s
+Display the users that are listed as members of the given group (ie
+supplementary group membership).
+Note that this does not list users that have the given group as their prim=
ary
+group.
 .It Fl u
 Display the effective user ID as a number.
 .El
Index: id.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/usr.bin/id/id.c,v
retrieving revision 1.27
diff -b -u -r1.27 id.c
--- id.c	7 Jun 2006 13:09:56 -0000	1.27
+++ id.c	17 Jun 2006 22:18:45 -0000
@@ -55,9 +55,11 @@
 static void current(void);
 static void pretty(struct passwd *);
 static void group(struct passwd *, int);
+static void sgroup(struct group *, int);
 static void usage(void);
 static void user(struct passwd *);
 static struct passwd *who(char *);
+static struct group *gwho(char *);
=20
 static int maxgroups;
 static gid_t *groups;
@@ -68,9 +70,12 @@
 	struct group *gr;
 	struct passwd *pw;
 	int ch, id;
-	int Gflag, gflag, nflag, pflag, rflag, uflag;
+	int Gflag, gflag, nflag, pflag, rflag, sflag, uflag;
=20
-	Gflag =3D gflag =3D nflag =3D pflag =3D rflag =3D uflag =3D 0;
+	Gflag =3D gflag =3D nflag =3D pflag =3D rflag =3D sflag =3D uflag =3D 0;
+
+	gr =3D NULL;
+	pw =3D NULL;
=20
 	if (strcmp(getprogname(), "groups") =3D=3D 0) {
 		Gflag =3D 1;
@@ -80,7 +85,7 @@
 		nflag =3D 1;
 	}
=20
-	while ((ch =3D getopt(argc, argv, "Ggnpru")) !=3D -1)
+	while ((ch =3D getopt(argc, argv, "Ggnprsu")) !=3D -1)
 		switch (ch) {
 		case 'G':
 			Gflag =3D 1;
@@ -97,6 +102,9 @@
 		case 'r':
 			rflag =3D 1;
 			break;
+		case 's':
+			sflag =3D 1;
+			break;
 		case 'u':
 			uflag =3D 1;
 			break;
@@ -107,7 +115,7 @@
 	argc -=3D optind;
 	argv +=3D optind;
=20
-	switch (Gflag + gflag + pflag + uflag) {
+	switch (Gflag + gflag + pflag + uflag + sflag) {
 	case 1:
 		break;
 	case 0:
@@ -118,6 +126,9 @@
 		usage();
 	}
=20
+	if (sflag)
+		gr =3D gwho(*argv);
+	else
 	pw =3D *argv ? who(*argv) : NULL;
=20
 	maxgroups =3D sysconf(_SC_NGROUPS_MAX);
@@ -152,6 +163,11 @@
 		goto done;
 	}
=20
+	if (sflag) {
+		sgroup(gr, nflag);
+		goto done;
+	}
+
 	if (pw)
 		user(pw);
 	else
@@ -318,6 +334,62 @@
 		free(glist);
 }
=20
+static void
+sgroup(struct group *gr, int nflag)
+{
+	char **gr_mem;
+	struct passwd *pw;
+	int cnt;
+
+	cnt =3D 0;
+
+	for ((gr_mem =3D gr->gr_mem); *gr_mem; ) {
+		cnt++;
+		if (!nflag) {
+			if ((pw =3D getpwnam(*gr_mem)) =3D=3D NULL) {
+				warnx("Nonexistent user '%s' in group '%s'",
+						*gr_mem, gr->gr_name);
+				gr_mem++;
+				continue;
+			}
+
+			(void)printf("%u", pw->pw_uid);
+		=09
+		} else=20
+			(void)printf("%s", *gr_mem);
+
+		if (*++gr_mem)
+			(void)printf(" ");
+	}
+	if (cnt)
+		(void)printf("\n");
+}
+
+static struct group *
+gwho(char *g)
+{
+	struct group *gr;
+	long id;
+	char *ep;
+
+	if (!g)
+		usage();
+		/* NOTREACHED */
+
+	/*
+	 * Translate user argument into a gr pointer.  First, try to
+	 * get it as specified.  If that fails, try it as a number.
+	 */
+	if ((gr =3D getgrnam(g)) !=3D NULL)
+		return gr;
+	id =3D strtol(g, &ep, 10);
+	if (*g && !*ep && (gr =3D getgrgid(id)))
+		return gr;
+	errx(1, "%s: No such group", g);
+	/* NOTREACHED */
+	return NULL;
+}
+
 static struct passwd *
 who(char *u)
 {
@@ -353,6 +425,7 @@
 		(void)fprintf(stderr, "       id -g [-nr] [user]\n");
 		(void)fprintf(stderr, "       id -p [user]\n");
 		(void)fprintf(stderr, "       id -u [-nr] [user]\n");
+		(void)fprintf(stderr, "       id -s [-n] group\n");
 	}
 	exit(1);
 }

--tEFtbjk+mNEviIIX--

--8vCeF2GUdMpe9ZbK
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (NetBSD)

iD8DBQFElIRLfFtkr68iakwRAmFBAJ9u5Ip7KGnRJ0MmV/2oT9QpVBi2TwCgqyQH
XDnPY1hvImzbFsJhGOMXMcg=
=pRqc
-----END PGP SIGNATURE-----

--8vCeF2GUdMpe9ZbK--