1 /*
2  * id - print user and group IDs and names
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, August 2002.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 #ifdef	SUS
36 static const char sccsid[] USED = "@(#)id_sus.sl	1.10 (gritter) 5/29/05";
37 #else
38 static const char sccsid[] USED = "@(#)id.sl	1.10 (gritter) 5/29/05";
39 #endif
40 
41 #include	<unistd.h>
42 #include	<stdio.h>
43 #include	<string.h>
44 #include	<stdlib.h>
45 #include	<errno.h>
46 #include	<libgen.h>
47 #include	<pwd.h>
48 #include	<grp.h>
49 
50 static int	aflag;			/* print supplementary GIDs */
51 static int	nflag;			/* print names instead of numbers */
52 static int	rflag;			/* use real IDs */
53 static int	restriction;		/* 'G' or 'g' or 'u' */
54 static char	*progname;		/* argv[0] to main() */
55 
56 static void *
srealloc(void * vp,size_t nbytes)57 srealloc(void *vp, size_t nbytes)
58 {
59 	void	*p;
60 
61 	if ((p = (void *)realloc(vp, nbytes)) == NULL) {
62 		write(2, "Out of memory\n", 14);
63 		exit(077);
64 	}
65 	return p;
66 }
67 
68 static void *
smalloc(size_t nbytes)69 smalloc(size_t nbytes)
70 {
71 	return srealloc(NULL, nbytes);
72 }
73 
74 static void
usage(void)75 usage(void)
76 {
77 #ifdef	SUS
78 	fprintf(stderr, "\
79 Usage: %s [user]\n\
80        %s -a [user]\n\
81        %s -G [-n] [user]\n\
82        %s -g [-nr] [user]\n\
83        %s -u [-nr] [user]\n",
84 		progname, progname, progname, progname, progname);
85 #else
86 	fprintf(stderr, "usage: %s [-a]\n", progname);
87 #endif
88 	exit(2);
89 }
90 
91 static int	putspace;
92 
93 static void
print_id(char * string,unsigned id,char * name)94 print_id(char *string, unsigned id, char *name)
95 {
96 	if (restriction) {
97 		if (putspace)
98 			putchar(' ');
99 		if (nflag)
100 			printf("%s", name);
101 		else
102 			printf("%u", id);
103 	} else {
104 		printf("%s%s=%u", putspace ? " " : "", string, id);
105 		if (name)
106 			printf("(%s)", name);
107 	}
108 	putspace++;
109 }
110 
111 static void
print_supp(unsigned id,char * name)112 print_supp(unsigned id, char *name)
113 {
114 	if (restriction) {
115 		if (putspace++)
116 			putchar(' ');
117 		if (nflag)
118 			printf("%s", name);
119 		else
120 			printf("%u", id);
121 	} else {
122 		static int	putcomma;
123 
124 		if (putcomma++ == 0)
125 			printf(" groups=");
126 		else
127 			putchar(',');
128 		printf("%u", id);
129 		if (name)
130 			printf("(%s)", name);
131 	}
132 }
133 
134 static void
supplementary(int me,char * name,gid_t mygid,gid_t myegid)135 supplementary(int me, char *name, gid_t mygid, gid_t myegid)
136 {
137 	struct group	*grp;
138 	gid_t	*groups;
139 	int	i, count;
140 
141 	if (me) {
142 		if ((count = getgroups(0, NULL)) > 0) {
143 
144 			groups = smalloc(count * sizeof *groups);
145 			getgroups(count, groups);
146 			for (i = 0; i < count; i++) {
147 				if (mygid != myegid || mygid != groups[i] ||
148 						aflag > 1)
149 				{
150 					grp = getgrgid(groups[i]);
151 					print_supp(groups[i], grp ?
152 						grp->gr_name : NULL);
153 				}
154 			}
155 			free(groups);
156 		}
157 	} else if (name) {
158 		setgrent();
159 		while ((grp = getgrent()) != NULL) {
160 			if (mygid != myegid || mygid != grp->gr_gid ||
161 					aflag > 1)
162 			{
163 				if (grp->gr_mem)
164 					for (i = 0; grp->gr_mem[i]; i++)
165 						if (strcmp(grp->gr_mem[i],
166 								name) == 0)
167 							print_supp(grp->gr_gid,
168 								grp->gr_name);
169 			}
170 		}
171 		endgrent();
172 	}
173 }
174 
175 static void
id(int me,uid_t uid,uid_t euid,gid_t gid,gid_t egid)176 id(int me, uid_t uid, uid_t euid, gid_t gid, gid_t egid)
177 {
178 	struct passwd	*pwd;
179 	struct group	*grp;
180 	char	*name;
181 
182 	pwd = getpwuid(uid);
183 	if (restriction == 0 || (restriction == 'u' && rflag))
184 		print_id("uid", uid, pwd ? pwd->pw_name : NULL);
185 	if (pwd) {
186 		name = smalloc(strlen(pwd->pw_name) + 1);
187 		strcpy(name, pwd->pw_name);
188 	} else
189 		name = NULL;
190 	grp = getgrgid(gid);
191 	if (restriction == 0 || (restriction == 'g' && rflag) ||
192 			restriction == 'G')
193 		print_id("gid", gid, grp ? grp->gr_name : NULL);
194 	if ((restriction == 0 && uid != euid) ||
195 			(restriction == 'u' && rflag == 0)) {
196 		pwd = getpwuid(euid);
197 		print_id("euid", euid, pwd ? pwd->pw_name : NULL);
198 	}
199 	if (((restriction == 0 || restriction == 'G') && gid != egid) ||
200 			(restriction == 'g' && rflag == 0)) {
201 		grp = getgrgid(egid);
202 		print_id("egid", egid, grp ? grp->gr_name : NULL);
203 	}
204 	if ((restriction == 0 && aflag) || restriction == 'G')
205 		supplementary(me, name, gid, egid);
206 	putchar('\n');
207 }
208 
209 int
main(int argc,char ** argv)210 main(int argc, char **argv)
211 {
212 #ifdef	SUS
213 	const char	optstring[] = "aGgnru";
214 #else
215 	const char	optstring[] = "a";
216 #endif
217 	int	i, me;
218 	uid_t	uid, euid;
219 	gid_t	gid, egid;
220 
221 #ifdef	__GLIBC__
222 	putenv("POSIXLY_CORRECT=1");
223 #endif
224 	progname = basename(argv[0]);
225 #ifdef	SUS
226 	aflag = 1;
227 #endif
228 	while ((i = getopt(argc, argv, optstring)) != EOF) {
229 		switch (i) {
230 		case 'a':
231 			aflag = 2;
232 			break;
233 		case 'n':
234 			nflag = 1;
235 			break;
236 		case 'r':
237 			rflag = 1;
238 			break;
239 		case 'G':
240 		case 'g':
241 		case 'u':
242 			if (restriction)
243 				usage();
244 			restriction = i;
245 			break;
246 		default:
247 			usage();
248 		}
249 	}
250 	if (restriction == 0 && (nflag || rflag))
251 		usage();
252 	if (restriction != 0 && aflag > 1)
253 		usage();
254 	if (restriction == 'G' && rflag)
255 		usage();
256 #ifdef	SUS
257 	if (argc - optind == 1) {
258 		struct passwd	*pwd;
259 
260 		if ((pwd = getpwnam(argv[optind])) == NULL) {
261 			fprintf(stderr, "%s: invalid user name: %s\n",
262 					progname, argv[optind]);
263 			exit(1);
264 		}
265 		me = 0;
266 		uid = euid = pwd->pw_uid;
267 		gid = egid = pwd->pw_gid;
268 	} else if (argc < optind > 1) {
269 		usage();
270 	} else
271 #endif	/* SUS */
272 	{
273 		me = 1;
274 		uid = getuid();
275 		euid = geteuid();
276 		gid = getgid();
277 		egid = getegid();
278 	}
279 	id(me, uid, euid, gid, egid);
280 	return 0;
281 }
282