*BSD News Article 11466


Return to BSD News archive

Received: by minnie.vk1xwt.ampr.org with NNTP
	id AA1678 ; Tue, 23 Feb 93 14:53:10 EST
Newsgroups: comp.unix.bsd,comp.os.386bsd.bugs
Path: sserve!manuel.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!sun-barr!cs.utexas.edu!uwm.edu!rpi!ghost.dsi.unimi.it!serini
From: serini@ghost.dsi.unimi.it (Piero Serini)
Subject: id(1) bugs and new source
Organization: Computer Science Dep. - Milan University
Date: Fri, 19 Feb 1993 13:54:50 GMT
Message-ID: <1993Feb19.135450.3052@ghost.dsi.unimi.it>
Summary: new id.c 
Lines: 374

Hi.

I found that id(1) doesn't handle properly the "gid"
and "groups" entries: 

1) "normal" id:
	$ id
	uid=100(piero) gid=20(staff) groups=5(opr), 20(staff)
	                              redundant     ^^^^^^^^

2) id [user] doesn't work: it uses the uid to seek for group name:
	$ id giulia
	uid=500(giulia) gid=100

   In /etc/group gid 100 = users, but id looks for 500 and doesn't
   find it. Another test:
	$ id piero (myself)
	uid=100(piero) gid=20(users) groups=5(opr)

   As you can see in the example at 1), gid 20 = staff,
   but id looks for 100 which is = users

3) after a setuid() AND a setgid(), "groups" is a mix between the original
   groups and the new ones. Here follows an id from a "super-shell":
	uid=0(root) gid=0(root) groups=0(root), 5(opr), 20(staff)

   uid and gid are right;
   groups: 0(root) is redundant (root has gid 0 = root)
           5(opr)  is wrong (piero is in group 5, not root)
	   20(staff) is right, but we can't tell: both piero
           and root are in group 20.

The new id.c source follows.
Bye all
-- 
------------------------------------------ Piero Serini ------------
Via Giambologna, 1             E-mail: piero@strider.st.dsi.unimi.it
20136 - Milano - ITALY             or: serini@ghost.dsi.unimi.it
-------- PUBLIC KEY AVAILABLE VIA finger(1) or mail request --------


/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)id.c	5.1 (Berkeley) 6/29/91";
#endif /* not lint */

#include <sys/param.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct passwd PW;
typedef struct group GR;

void	err __P((const char *, ...));
int	gcmp __P((const void *, const void *));
void	sgroup __P((PW *));
void	ugroup __P((PW *));
void	usage __P((void));
void	user __P((PW *));
PW     *who __P((char *));

int Gflag, gflag, nflag, rflag, uflag;

main(argc, argv)
	int argc;
	char *argv[];
{
	GR *gr;
	PW *pw;
	int ch, id;

	while ((ch = getopt(argc, argv, "Ggnru")) != EOF)
		switch(ch) {
		case 'G':
			Gflag = 1;
			break;
		case 'g':
			gflag = 1;
			break;
		case 'n':
			nflag = 1;
			break;
		case 'r':
			rflag = 1;
			break;
		case 'u':
			uflag = 1;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	pw = *argv ? who(*argv) : NULL;

	if (Gflag + gflag + uflag > 1)
		usage();

	if (Gflag) {
		if (nflag)
			sgroup(pw);
		else
			ugroup(pw);
		exit(0);
	}

	if (gflag) {
		id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
		if (nflag && (gr = getgrgid(id))) {
			(void)printf("%s\n", gr->gr_name);
			exit(0);
		}
		(void)printf("%u\n", id);
		exit(0);
	}

	if (uflag) {
		id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
		if (nflag && (pw = getpwuid(id))) {
			(void)printf("%s\n", pw->pw_name);
			exit(0);
		}
		(void)printf("%u\n", id);
		exit(0);
	}

	if (!pw)
		pw = getpwuid(getuid());

	user(pw);
	exit(0);
}

void
sgroup(pw)
	PW *pw;
{
	register int id, lastid;
	char *fmt;

	if (pw) {
		register GR *gr;
		register char *name, **p;

		name = pw->pw_name;
		for (fmt = "%s", lastid = -1; gr = getgrent(); lastid = id) {
			for (p = gr->gr_mem; p && *p; p++)
				if (!strcmp(*p, name)) {
					(void)printf(fmt, gr->gr_name);
					fmt = " %s";
					break;
				}
		}
	} else {
		GR *gr;
		register int ngroups;
		int groups[NGROUPS + 1];

		groups[0] = getgid();
		ngroups = getgroups(NGROUPS, groups + 1) + 1;
		heapsort(groups, ngroups, sizeof(groups[0]), gcmp);
		for (fmt = "%s", lastid = -1; --ngroups >= 0;) {
			if (lastid == (id = groups[ngroups]))
				continue;
			if (gr = getgrgid(id))
				(void)printf(fmt, gr->gr_name);
			else
				(void)printf(*fmt == ' ' ? " %u" : "%u", id);
			fmt = " %s";
			lastid = id;
		}
	}
	(void)printf("\n");
}

void
ugroup(pw)
	PW *pw;
{
	register int id, lastid;
	register char *fmt;

	if (pw) {
		register GR *gr;
		register char *name, **p;

		name = pw->pw_name;
		for (fmt = "%u", lastid = -1; gr = getgrent(); lastid = id) {
			for (p = gr->gr_mem; p && *p; p++)
				if (!strcmp(*p, name)) {
					(void)printf(fmt, gr->gr_gid);
					fmt = " %u";
					break;
				}
		}
	} else {
		register int ngroups;
		int groups[NGROUPS + 1];

		groups[0] = getgid();
		ngroups = getgroups(NGROUPS, groups + 1) + 1;
		heapsort(groups, ngroups, sizeof(groups[0]), gcmp);
		for (fmt = "%u", lastid = -1; --ngroups >= 0;) {
			if (lastid == (id = groups[ngroups]))
				continue;
			(void)printf(fmt, id);
			fmt = " %u";
			lastid = id;
		}
	}
	(void)printf("\n");
}

void
user(pw)
	register PW *pw;
{
	register GR *gr;
	register int id, lastid;
	int	 eid, gid, egid;
	register char *fmt, **p;

	id = pw->pw_uid;
	gid = pw->pw_gid;

	(void)printf("uid=%u(%s)", id, pw->pw_name);

	if (id == getuid())
		if ((eid = geteuid()) != id) {
			(void)printf(" euid=%u", eid);
			if (pw = getpwuid(eid))
				(void)printf("(%s)", pw->pw_name);
		}
	/* endif id == getuid() */

	(void)printf(" gid=%u", gid);
	if (gr = getgrgid(gid))
		(void)printf("(%s)", gr->gr_name);

        if (id == getuid())
		if ((egid = getegid()) != gid) {
			(void)printf(" egid=%u", egid);
			if (gr = getgrgid(egid))
				(void)printf("(%s)", gr->gr_name);
		}
        /* endif id == getuid() */

	/* now pw points to Euid, so we must reset it */
	pw = getpwuid(id);
	for (fmt = " groups=%u(%s)", lastid = -1; gr = getgrent();
	    lastid = id) {
		if (pw->pw_gid == gr->gr_gid)
			continue;
		for (p = gr->gr_mem; p && *p; p++)
			if (!strcmp(*p, pw->pw_name)) {
				(void)printf(fmt, gr->gr_gid, gr->gr_name);
				fmt = ", %u(%s)";
				break;
			}
	}
	(void)printf("\n");
}

PW *
who(u)
	char *u;
{
	PW *pw;
	long id;
	char *ep;

	/*
	 * Translate user argument into a pw pointer.  First, try to
	 * get it as specified.  If that fails, try it as a number.
	 */
	if (pw = getpwnam(u))
		return(pw);
	id = strtol(u, &ep, 10);
	if (*u && !*ep && (pw = getpwuid(id)))
		return(pw);
	err("%s: No such user", u);
	/* NOTREACHED */
}

gcmp(a, b)
	const void *a, *b;
{
	return(*(int *)b - *(int *)a);
}

#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
	char *fmt;
        va_dcl
#endif
{
	va_list ap;
#if __STDC__
	va_start(ap, fmt);
#else
	va_start(ap);
#endif
	(void)fprintf(stderr, "id: ");
	(void)vfprintf(stderr, fmt, ap);
	va_end(ap);
	(void)fprintf(stderr, "\n");
	exit(1);
	/* NOTREACHED */
}

void
usage()
{
	(void)fprintf(stderr, "usage: id [user]\n");
	(void)fprintf(stderr, "       id -G [-n] [user]\n");
	(void)fprintf(stderr, "       id -g [-nr] [user]\n");
	(void)fprintf(stderr, "       id -u [-nr] [user]\n");
	exit(1);
}