xref: /illumos-gate/usr/src/contrib/ast/src/lib/libcmd/id.c (revision b30d1939)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 
30 static const char usage[] =
31 "[-?\n@(#)$Id: id (AT&T Research) 2004-06-11 $\n]"
32 USAGE_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
102 static void
getfsids(Sfio_t * sp,const char * name,int flags,register int lastchar)103 getfsids(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 
177 static void
putid(Sfio_t * sp,int flags,const char * label,const char * name,long number)178 putid(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 
193 static int
getids(Sfio_t * sp,const char * name,register int flags)194 getids(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 
418 int
b_id(int argc,char ** argv,Shbltin_t * context)419 b_id(int argc, char** argv, Shbltin_t* context)
420 {
421 	register int	flags = 0;
422 	register int	n;
423 
424 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
425 	for (;;)
426 	{
427 		switch (optget(argv, usage))
428 		{
429 		case 'a':
430 			continue;
431 		case 'G':
432 			flags |= GG_FLAG;
433 			continue;
434 		case 'g':
435 			flags |= G_FLAG;
436 			continue;
437 		case 'n':
438 			flags |= N_FLAG;
439 			continue;
440 		case 'r':
441 			flags |= R_FLAG;
442 			continue;
443 		case 's':
444 			flags |= S_FLAG;
445 			continue;
446 		case 'u':
447 			flags |= U_FLAG;
448 			continue;
449 		case ':':
450 			error(2, "%s", opt_info.arg);
451 			break;
452 		case '?':
453 			error(ERROR_usage(2), "%s", opt_info.arg);
454 			break;
455 		}
456 		break;
457 	}
458 	argv += opt_info.index;
459 	argc -= opt_info.index;
460 	n = (flags & (GG_FLAG|G_FLAG|S_FLAG|U_FLAG));
461 	if (!power2(n))
462 		error(2, "incompatible options selected");
463 	if (error_info.errors || argc > 1)
464 		error(ERROR_usage(2), "%s", optusage(NiL));
465 	if (!(flags & ~(N_FLAG|R_FLAG)))
466 	{
467 		if (flags & N_FLAG) flags |= O_FLAG;
468 		flags |= (U_FLAG|G_FLAG|N_FLAG|R_FLAG|S_FLAG|GG_FLAG);
469 	}
470 	error_info.errors = getids(sfstdout, *argv, flags);
471 	return(error_info.errors);
472 }
473