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