1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1992-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
19da2e3ebchin*                                                                      *
20da2e3ebchin***********************************************************************/
21da2e3ebchin#pragma prototyped
22da2e3ebchin/*
23da2e3ebchin * David Korn
24da2e3ebchin * Glenn Fowler
25da2e3ebchin * AT&T Research
26da2e3ebchin *
27da2e3ebchin * id
28da2e3ebchin */
29da2e3ebchin
30da2e3ebchinstatic const char usage[] =
31da2e3ebchin"[-?\n@(#)$Id: id (AT&T Research) 2004-06-11 $\n]"
32da2e3ebchinUSAGE_LICENSE
33da2e3ebchin"[+NAME?id - return user identity]"
34da2e3ebchin"[+DESCRIPTION?If no \auser\a operand is specified \bid\b writes user and "
35da2e3ebchin	"group IDs and the corresponding user and group names of the "
36da2e3ebchin	"invoking process to standard output.  If the effective and "
37da2e3ebchin	"real IDs do not match, both are written.  Any supplementary "
38da2e3ebchin	"groups the current process belongs to will also be written.]"
39da2e3ebchin"[+?If a \auser\a operand is specified and the process has permission, "
40da2e3ebchin	"the user and group IDs and any supplementary group IDs of the "
41da2e3ebchin	"selected user will be written to standard output.]"
42da2e3ebchin"[+?If any options are specified, then only a portion of the information "
43da2e3ebchin	"is written.]"
44da2e3ebchin"[n:name?Write the name instead of the numeric ID.]"
45da2e3ebchin"[r:real?Writes real ID instead of the effective ID.]"
46da2e3ebchin"[[a?This option is ignored.]"
47da2e3ebchin"[g:group?Writes only the group ID.]"
48da2e3ebchin"[u:user?Writes only the user ID.]"
49da2e3ebchin"[G:groups?Writes only the supplementary group IDs.]"
50da2e3ebchin"[s:fair-share?Writes fair share scheduler IDs and groups on systems that "
51da2e3ebchin	"support fair share scheduling.]"
52da2e3ebchin"\n"
53da2e3ebchin"\n[user]\n"
54da2e3ebchin"\n"
55da2e3ebchin"[+EXIT STATUS?]{"
56da2e3ebchin        "[+0?Successful completion.]"
57da2e3ebchin        "[+>0?An error occurred.]"
58da2e3ebchin"}"
59da2e3ebchin"[+SEE ALSO?\blogname\b(1), \bwho\b(1), \bgetgroups\b(2)]"
60da2e3ebchin;
61da2e3ebchin
62da2e3ebchin#include <cmd.h>
63da2e3ebchin
64da2e3ebchin#include "FEATURE/ids"
65da2e3ebchin
66da2e3ebchin#include <grp.h>
67da2e3ebchin#include <pwd.h>
68da2e3ebchin
69da2e3ebchin#if _lib_fsid
70da2e3ebchin#if _lib_getfsgid && ( _sys_fss || _hdr_fsg )
71da2e3ebchin#define fss_grp		fs_grp
72da2e3ebchin#define fss_id		fs_id
73da2e3ebchin#define fss_mem		fs_mem
74da2e3ebchin#define fss_passwd	fs_passwd
75da2e3ebchin#define fss_shares	fs_shares
76da2e3ebchin#if _sys_fss
77da2e3ebchin#include <sys/fss.h>
78da2e3ebchin#endif
79da2e3ebchin#if _hdr_fsg
80da2e3ebchin#include <fsg.h>
81da2e3ebchin#endif
82da2e3ebchin#if !_lib_isfsg && !defined(isfsg)
83da2e3ebchin#define isfsg(p)	(!(p)->fs_id&&!(p)->fs_shares&&(!(p)->fs_passwd||!*(p)->fs_passwd))
84da2e3ebchin#endif
85da2e3ebchin#else
86da2e3ebchin#undef _lib_fsid
87da2e3ebchin#endif
88da2e3ebchin#endif
89da2e3ebchin
90da2e3ebchin#define power2(n)	(!((n)&((n)-1)))
91da2e3ebchin
92da2e3ebchin#define GG_FLAG		(1<<0)
93da2e3ebchin#define G_FLAG		(1<<1)
94da2e3ebchin#define N_FLAG		(1<<2)
95da2e3ebchin#define R_FLAG		(1<<3)
96da2e3ebchin#define U_FLAG		(1<<4)
97da2e3ebchin#define S_FLAG		(1<<5)
98da2e3ebchin#define O_FLAG		(1<<6)
99da2e3ebchin#define X_FLAG		(1<<7)
100da2e3ebchin
101da2e3ebchin#if _lib_fsid
102da2e3ebchinstatic void
103da2e3ebchingetfsids(Sfio_t* sp, const char* name, int flags, register int lastchar)
104da2e3ebchin{
105da2e3ebchin	register struct fsg*	fs;
106da2e3ebchin	register char*		s;
107da2e3ebchin	register char**		p;
108da2e3ebchin	char**			x;
109da2e3ebchin
110da2e3ebchin	if (lastchar)
111da2e3ebchin	{
112da2e3ebchin		if (flags & O_FLAG) flags = 1;
113da2e3ebchin		else flags = 0;
114da2e3ebchin	}
115da2e3ebchin	else if (flags & N_FLAG) flags = 1;
116da2e3ebchin	else flags = -1;
117da2e3ebchin	setfsgent();
118da2e3ebchin	while (fs = getfsgnam(name))
119da2e3ebchin		if (!isfsg(fs))
120da2e3ebchin		{
121da2e3ebchin			if (p = fs->fs_mem)
122da2e3ebchin			{
123da2e3ebchin				if (flags > 0) x = 0;
124da2e3ebchin				else
125da2e3ebchin				{
126da2e3ebchin					register char**		q;
127da2e3ebchin					register char*		t;
128da2e3ebchin					register int		n;
129da2e3ebchin
130da2e3ebchin					n = 0;
131da2e3ebchin					q = p;
132da2e3ebchin					while (s = *q++)
133da2e3ebchin						n += strlen(s) + 1;
134da2e3ebchin					if (!(x = newof(0, char*, q - p, n)))
135da2e3ebchin						break;
136da2e3ebchin					s = (char*)(x + (q - p));
137da2e3ebchin					q = x;
138da2e3ebchin					while (t = *p++)
139da2e3ebchin					{
140da2e3ebchin						*q++ = s;
141da2e3ebchin						while (*s++ = *t++);
142da2e3ebchin					}
143da2e3ebchin					*q = 0;
144da2e3ebchin					p = x;
145da2e3ebchin				}
146da2e3ebchin				while (s = *p++)
147da2e3ebchin				{
148da2e3ebchin					if (lastchar == '=')
149da2e3ebchin					{
150da2e3ebchin						lastchar = ',';
151da2e3ebchin						sfputr(sp, " fsid=", -1);
152da2e3ebchin					}
153da2e3ebchin					else if (!lastchar) lastchar = ' ';
154da2e3ebchin					else sfputc(sp, lastchar);
155da2e3ebchin					if (flags > 0) sfprintf(sp, "%s", s);
156da2e3ebchin					else
157da2e3ebchin					{
158da2e3ebchin						setfsgent();
159da2e3ebchin						while (fs = getfsgnam(s))
160da2e3ebchin							if (isfsg(fs))
161da2e3ebchin							{
162da2e3ebchin								if (flags < 0) sfprintf(sp, "%u", fs->fs_id);
163da2e3ebchin								else sfprintf(sp, "%u(%s)", fs->fs_id, s);
164da2e3ebchin								break;
165da2e3ebchin							}
166da2e3ebchin					}
167da2e3ebchin				}
168da2e3ebchin				if (x) free(x);
169da2e3ebchin			}
170da2e3ebchin			break;
171da2e3ebchin		}
172da2e3ebchin	endfsgent();
173da2e3ebchin	if (lastchar == ' ') sfputc(sp, '\n');
174da2e3ebchin}
175da2e3ebchin#endif
176da2e3ebchin
177da2e3ebchinstatic void
178da2e3ebchinputid(Sfio_t* sp, int flags, const char* label, const char* name, long number)
179da2e3ebchin{
180da2e3ebchin	sfprintf(sp, "%s=", label);
181da2e3ebchin	if (flags & O_FLAG)
182da2e3ebchin	{
183da2e3ebchin		if (name) sfputr(sp, name, -1);
184da2e3ebchin		else sfprintf(sp, "%lu", number);
185da2e3ebchin	}
186da2e3ebchin	else
187da2e3ebchin	{
188da2e3ebchin		sfprintf(sp, "%u", number);
189da2e3ebchin		if (name) sfprintf(sp, "(%s)", name);
190da2e3ebchin	}
191da2e3ebchin}
192da2e3ebchin
193da2e3ebchinstatic int
194da2e3ebchingetids(Sfio_t* sp, const char* name, register int flags)
195da2e3ebchin{
196da2e3ebchin	register struct passwd*	pw;
197da2e3ebchin	register struct group*	grp;
198da2e3ebchin	register int		i;
199da2e3ebchin	register int		j;
200da2e3ebchin	register int		k;
201da2e3ebchin#if _lib_fsid
202da2e3ebchin	register struct fsg*	fs;
203da2e3ebchin	const char*		fs_name;
204da2e3ebchin	int			fs_id;
205da2e3ebchin#endif
206da2e3ebchin	char**			p;
207da2e3ebchin	char*			s;
208da2e3ebchin	int			lastchar;
209da2e3ebchin	int			ngroups = 0;
210da2e3ebchin	const char*		gname;
211da2e3ebchin	uid_t			user;
212da2e3ebchin	uid_t			euid;
213da2e3ebchin	gid_t			group;
214da2e3ebchin	gid_t			egid;
215da2e3ebchin
216da2e3ebchin	static gid_t*		groups;
217da2e3ebchin
218da2e3ebchin	if (flags & GG_FLAG)
219da2e3ebchin	{
220da2e3ebchin		static int	maxgroups;
221da2e3ebchin
222da2e3ebchin		/*
223da2e3ebchin		 * get supplemental groups if required
224da2e3ebchin		 */
225da2e3ebchin
226da2e3ebchin		if (!maxgroups)
227da2e3ebchin		{
228da2e3ebchin			/*
229da2e3ebchin			 * first time
230da2e3ebchin			 */
231da2e3ebchin
232da2e3ebchin			if ((maxgroups = getgroups(0, groups)) <= 0)
233da2e3ebchin				maxgroups = NGROUPS_MAX;
234da2e3ebchin			if (!(groups = newof(0, gid_t, maxgroups + 1, 0)))
235da2e3ebchin				error(ERROR_exit(1), "out of space [group array]");
236da2e3ebchin		}
237da2e3ebchin		ngroups = getgroups(maxgroups, groups);
238da2e3ebchin		for (i = j = 0; i < ngroups; i++)
239da2e3ebchin		{
240da2e3ebchin			for (k = 0; k < j && groups[k] != groups[i]; k++);
241da2e3ebchin			if (k >= j) groups[j++] = groups[i];
242da2e3ebchin		}
243da2e3ebchin		ngroups = j;
244da2e3ebchin	}
245da2e3ebchin	if (name)
246da2e3ebchin	{
247da2e3ebchin		flags |= X_FLAG;
248da2e3ebchin		if (!(flags & N_FLAG) || (flags & (G_FLAG|GG_FLAG)))
249da2e3ebchin		{
250da2e3ebchin			if (!(pw = getpwnam(name)))
251da2e3ebchin			{
252da2e3ebchin				user = strtol(name, &s, 0);
253da2e3ebchin				if (*s || !(pw = getpwuid(user)))
254da2e3ebchin					error(ERROR_exit(1), "%s: name not found", name);
255da2e3ebchin				name = pw->pw_name;
256da2e3ebchin			}
257da2e3ebchin			user = pw->pw_uid;
258da2e3ebchin			group = pw->pw_gid;
259da2e3ebchin		}
260da2e3ebchin#if _lib_fsid
261da2e3ebchin		if (!(flags & N_FLAG) || (flags & S_FLAG))
262da2e3ebchin		{
263da2e3ebchin			setfsgent();
264da2e3ebchin			do
265da2e3ebchin                        {
266da2e3ebchin                                if (!(fs = getfsgnam(name)))
267da2e3ebchin                                        error(ERROR_exit(1), "%u: fss name not found", name);
268da2e3ebchin                        } while (isfsg(fs));
269da2e3ebchin                        fs_id = fs->fs_id;
270da2e3ebchin		}
271da2e3ebchin#endif
272da2e3ebchin	}
273da2e3ebchin	else
274da2e3ebchin	{
275da2e3ebchin		if (flags & G_FLAG)
276da2e3ebchin			group = (flags & R_FLAG) ? getgid() : getegid();
277da2e3ebchin		if (flags & (GG_FLAG|N_FLAG|U_FLAG))
278da2e3ebchin			user = (flags & R_FLAG) ? getuid() : geteuid();
279da2e3ebchin#if _lib_fsid
280da2e3ebchin		if (flags & S_FLAG)
281da2e3ebchin			fs_id = fsid(0);
282da2e3ebchin#endif
283da2e3ebchin		if (flags & N_FLAG)
284da2e3ebchin			name = (pw = getpwuid(user)) ? pw->pw_name : (char*)0;
285da2e3ebchin	}
286da2e3ebchin	if (ngroups == 1 && groups[0] == group)
287da2e3ebchin		ngroups = 0;
288da2e3ebchin	if ((flags & N_FLAG) && (flags & G_FLAG))
289da2e3ebchin		gname = (grp = getgrgid(group)) ? grp->gr_name : (char*)0;
290da2e3ebchin#if _lib_fsid
291da2e3ebchin	if ((flags & N_FLAG) && (flags & S_FLAG))
292da2e3ebchin	{
293da2e3ebchin		setfsgent();
294da2e3ebchin		fs_name = (fs = getfsgid(fs_id)) ? fs->fs_grp : (char*)0;
295da2e3ebchin	}
296da2e3ebchin#endif
297da2e3ebchin	if ((flags & (U_FLAG|G_FLAG|S_FLAG)) == (U_FLAG|G_FLAG|S_FLAG))
298da2e3ebchin	{
299da2e3ebchin		putid(sp, flags, "uid", name, user);
300da2e3ebchin		putid(sp, flags, " gid", gname, group);
301da2e3ebchin		if ((flags & X_FLAG) && name)
302da2e3ebchin		{
303da2e3ebchin#if _lib_getgrent
304da2e3ebchin#if _lib_setgrent
305da2e3ebchin			setgrent();
306da2e3ebchin#endif
307da2e3ebchin			lastchar = '=';
308da2e3ebchin			while (grp = getgrent())
309da2e3ebchin				if (p = grp->gr_mem)
310da2e3ebchin					while (s = *p++)
311da2e3ebchin						if (streq(s, name))
312da2e3ebchin						{
313da2e3ebchin							if (lastchar == '=')
314da2e3ebchin								sfputr(sp, " groups", -1);
315da2e3ebchin							sfputc(sp, lastchar);
316da2e3ebchin							lastchar = ',';
317da2e3ebchin							if (flags & O_FLAG)
318da2e3ebchin								sfprintf(sp, "%s", grp->gr_name);
319da2e3ebchin							else sfprintf(sp, "%u(%s)", grp->gr_gid, grp->gr_name);
320da2e3ebchin						}
321da2e3ebchin#if _lib_endgrent
322da2e3ebchin			endgrent();
323da2e3ebchin#endif
324da2e3ebchin#endif
325da2e3ebchin#if _lib_fsid
326da2e3ebchin			getfsids(sp, name, flags, '=');
327da2e3ebchin#endif
328da2e3ebchin		}
329da2e3ebchin		else
330da2e3ebchin		{
331da2e3ebchin			if ((euid = geteuid()) != user)
332da2e3ebchin				putid(sp, flags, " euid", (pw = getpwuid(euid)) ? pw->pw_name : (char*)0, euid);
333da2e3ebchin			if ((egid = getegid()) != group)
334da2e3ebchin				putid(sp, flags, " egid", (grp = getgrgid(egid)) ? grp->gr_name : (char*)0, egid);
335da2e3ebchin			if (ngroups > 0)
336da2e3ebchin			{
337da2e3ebchin				sfputr(sp, " groups", -1);
338da2e3ebchin				lastchar = '=';
339da2e3ebchin				for (i = 0; i < ngroups; i++)
340da2e3ebchin				{
341da2e3ebchin					group = groups[i];
342da2e3ebchin					sfputc(sp, lastchar);
343da2e3ebchin					if (grp = getgrgid(group))
344da2e3ebchin					{
345da2e3ebchin						if (flags & O_FLAG) sfprintf(sp, "%s", grp->gr_name);
346da2e3ebchin						else sfprintf(sp, "%u(%s)", group, grp->gr_name);
347da2e3ebchin					}
348da2e3ebchin					else sfprintf(sp, "%u", group);
349da2e3ebchin					lastchar = ',';
350da2e3ebchin				}
351da2e3ebchin			}
352da2e3ebchin#if _lib_fsid
353da2e3ebchin			putid(sp, flags, " fsid", fs_name, fs_id);
354da2e3ebchin#endif
355da2e3ebchin		}
356da2e3ebchin		sfputc(sp,'\n');
357da2e3ebchin		return(0);
358da2e3ebchin	}
359da2e3ebchin	if (flags & U_FLAG)
360da2e3ebchin	{
361da2e3ebchin		if ((flags & N_FLAG) && name) sfputr(sp, name, '\n');
362da2e3ebchin		else sfprintf(sp, "%u\n", user);
363da2e3ebchin	}
364da2e3ebchin	else if (flags & G_FLAG)
365da2e3ebchin	{
366da2e3ebchin		if ((flags & N_FLAG) && gname) sfputr(sp, gname, '\n');
367da2e3ebchin		else sfprintf(sp, "%u\n", group);
368da2e3ebchin	}
369da2e3ebchin	else if (flags & GG_FLAG)
370da2e3ebchin	{
371da2e3ebchin		if ((flags & X_FLAG) && name)
372da2e3ebchin		{
373da2e3ebchin#if _lib_getgrent
374da2e3ebchin#if _lib_setgrent
375da2e3ebchin			setgrent();
376da2e3ebchin#endif
377da2e3ebchin			i = 0;
378da2e3ebchin			while (grp = getgrent())
379da2e3ebchin				if (p = grp->gr_mem)
380da2e3ebchin					while (s = *p++)
381da2e3ebchin						if (streq(s, name))
382da2e3ebchin						{
383da2e3ebchin							if (i++) sfputc(sp, ' ');
384da2e3ebchin							if (flags & N_FLAG) sfprintf(sp, "%s", grp->gr_name);
385da2e3ebchin							else sfprintf(sp, "%u", grp->gr_gid);
386da2e3ebchin						}
387da2e3ebchin#if _lib_endgrent
388da2e3ebchin			endgrent();
389da2e3ebchin#endif
390da2e3ebchin			if (i) sfputc(sp, '\n');
391da2e3ebchin#endif
392da2e3ebchin		}
393da2e3ebchin		else if (ngroups > 0)
394da2e3ebchin		{
395da2e3ebchin			for (i = 0;;)
396da2e3ebchin			{
397da2e3ebchin				group = groups[i];
398da2e3ebchin				if ((flags & N_FLAG) && (grp = getgrgid(group)))
399da2e3ebchin					sfprintf(sp, "%s", grp->gr_name);
400da2e3ebchin				else sfprintf(sp, "%u", group);
401da2e3ebchin				if (++i >= ngroups) break;
402da2e3ebchin				sfputc(sp, ' ');
403da2e3ebchin			}
404da2e3ebchin			sfputc(sp, '\n');
405da2e3ebchin		}
406da2e3ebchin	}
407da2e3ebchin#if _lib_fsid
408da2e3ebchin	else if (flags & S_FLAG)
409da2e3ebchin	{
410da2e3ebchin		if ((flags & X_FLAG) && name) getfsids(sp, name, flags, 0);
411da2e3ebchin		else if ((flags & N_FLAG) && fs_name) sfputr(sp, fs_name, '\n');
412da2e3ebchin		else sfprintf(sp, "%u\n", fs_id);
413da2e3ebchin	}
414da2e3ebchin#endif
415da2e3ebchin	return(0);
416da2e3ebchin}
417da2e3ebchin
418da2e3ebchinint
419da2e3ebchinb_id(int argc, char *argv[], void* context)
420da2e3ebchin{
421da2e3ebchin	register int	flags = 0;
422da2e3ebchin	register int	n;
423da2e3ebchin
424da2e3ebchin	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
425da2e3ebchin	while (n = optget(argv, usage)) switch (n)
426da2e3ebchin	{
427da2e3ebchin	case 'a':
428da2e3ebchin		break;
429da2e3ebchin	case 'G':
430da2e3ebchin		flags |= GG_FLAG;
431da2e3ebchin		break;
432da2e3ebchin	case 'g':
433da2e3ebchin		flags |= G_FLAG;
434da2e3ebchin		break;
435da2e3ebchin	case 'n':
436da2e3ebchin		flags |= N_FLAG;
437da2e3ebchin		break;
438da2e3ebchin	case 'r':
439da2e3ebchin		flags |= R_FLAG;
440da2e3ebchin		break;
441da2e3ebchin	case 's':
442da2e3ebchin		flags |= S_FLAG;
443da2e3ebchin		break;
444da2e3ebchin	case 'u':
445da2e3ebchin		flags |= U_FLAG;
446da2e3ebchin		break;
447da2e3ebchin	case ':':
448da2e3ebchin		error(2, "%s", opt_info.arg);
449da2e3ebchin		break;
450da2e3ebchin	case '?':
451da2e3ebchin		error(ERROR_usage(2), "%s", opt_info.arg);
452da2e3ebchin		break;
453da2e3ebchin	}
454da2e3ebchin	argv += opt_info.index;
455da2e3ebchin	argc -= opt_info.index;
456da2e3ebchin	n = (flags & (GG_FLAG|G_FLAG|S_FLAG|U_FLAG));
457da2e3ebchin	if (!power2(n))
458da2e3ebchin		error(2, "incompatible options selected");
459da2e3ebchin	if (error_info.errors || argc > 1)
460da2e3ebchin		error(ERROR_usage(2), "%s", optusage(NiL));
461da2e3ebchin	if (!(flags & ~(N_FLAG|R_FLAG)))
462da2e3ebchin	{
463da2e3ebchin		if (flags & N_FLAG) flags |= O_FLAG;
464da2e3ebchin		flags |= (U_FLAG|G_FLAG|N_FLAG|R_FLAG|S_FLAG|GG_FLAG);
465da2e3ebchin	}
466da2e3ebchin	error_info.errors = getids(sfstdout, *argv, flags);
467da2e3ebchin	return(error_info.errors);
468da2e3ebchin}
469