xref: /titanic_52/usr/src/cmd/id/id.c (revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6)
1  /*
2   * CDDL HEADER START
3   *
4   * The contents of this file are subject to the terms of the
5   * Common Development and Distribution License (the "License").
6   * You may not use this file except in compliance with the License.
7   *
8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9   * or http://www.opensolaris.org/os/licensing.
10   * See the License for the specific language governing permissions
11   * and limitations under the License.
12   *
13   * When distributing Covered Code, include this CDDL HEADER in each
14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15   * If applicable, add the following below this CDDL HEADER, with the
16   * fields enclosed by brackets "[]" replaced with your own identifying
17   * information: Portions Copyright [yyyy] [name of copyright owner]
18   *
19   * CDDL HEADER END
20   */
21  /*
22   * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23   * Use is subject to license terms.
24   */
25  
26  #pragma ident	"%Z%%M%	%I%	%E% SMI"
27  
28  /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29  /*	  All Rights Reserved  	*/
30  
31  
32  #include <locale.h>
33  #include <stdio.h>
34  #include <pwd.h>
35  #include <grp.h>
36  #include <sys/param.h>
37  #include <unistd.h>
38  #include <string.h>
39  #include <project.h>
40  #include <stdlib.h>
41  #include <alloca.h>
42  
43  #define	PWNULL  ((struct passwd *)0)
44  #define	GRNULL  ((struct group *)0)
45  
46  typedef enum TYPE {
47  	UID, EUID, GID, EGID, SGID
48  }	TYPE;
49  
50  typedef enum PRINT {
51  	CURR,		/* Print uid/gid only */
52  	ALLGROUPS,	/* Print all groups */
53  	GROUP,		/* Print only group */
54  	USER		/* Print only uid */
55  }	PRINT;
56  static PRINT mode = CURR;
57  
58  static int usage(void);
59  static void puid(uid_t);
60  static void pgid(gid_t);
61  static void prid(TYPE, uid_t);
62  static int getusergroups(int, gid_t *, char *, gid_t);
63  
64  static int nflag = 0;		/* Output names, not numbers */
65  static int rflag = 0;		/* Output real, not effective IDs */
66  static char stdbuf[BUFSIZ];
67  
68  int
69  main(int argc, char *argv[])
70  {
71  	gid_t *idp;
72  	uid_t uid, euid;
73  	gid_t gid, egid, prgid;
74  	int c, aflag = 0, project_flag = 0;
75  	struct passwd *pwp;
76  	int i, j;
77  	int groupmax = sysconf(_SC_NGROUPS_MAX);
78  	gid_t *groupids = alloca(groupmax * sizeof (gid_t));
79  	struct group *gr;
80  	char *user = NULL;
81  
82  	(void) setlocale(LC_ALL, "");
83  
84  #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
85  #define	TEXT_DOMAIN "SYS_TEST"
86  #endif
87  	(void) textdomain(TEXT_DOMAIN);
88  	while ((c = getopt(argc, argv, "Ggunarp")) != EOF) {
89  		switch (c) {
90  			case 'G':
91  				if (mode != CURR)
92  					return (usage());
93  				mode = ALLGROUPS;
94  				break;
95  
96  			case 'g':
97  				if (mode != CURR)
98  					return (usage());
99  				mode = GROUP;
100  				break;
101  
102  			case 'a':
103  				aflag++;
104  				break;
105  
106  			case 'n':
107  				nflag++;
108  				break;
109  
110  			case 'r':
111  				rflag++;
112  				break;
113  
114  			case 'u':
115  				if (mode != CURR)
116  					return (usage());
117  				mode = USER;
118  				break;
119  
120  			case 'p':
121  				if (mode != CURR)
122  					return (usage());
123  				project_flag++;
124  				break;
125  
126  			case '?':
127  				return (usage());
128  		}
129  	}
130  	setbuf(stdout, stdbuf);
131  	argc -= optind-1;
132  	argv += optind-1;
133  
134  	/* -n and -r must be combined with one of -[Ggu] */
135  	/* -r cannot be combined with -G */
136  	/* -a and -p cannot be combined with -[Ggu] */
137  
138  	if ((mode == CURR && (nflag || rflag)) ||
139  		(mode == ALLGROUPS && rflag) ||
140  		(argc != 1 && argc != 2) ||
141  		(mode != CURR && (project_flag || aflag)))
142  		return (usage());
143  	if (argc == 2) {
144  		if ((pwp = getpwnam(argv[1])) == PWNULL) {
145  			(void) fprintf(stderr,
146  				gettext("id: invalid user name: \"%s\"\n"),
147  					argv[1]);
148  			return (1);
149  		}
150  		user = argv[1];
151  		uid = euid = pwp->pw_uid;
152  		prgid = gid = egid = pwp->pw_gid;
153  	} else {
154  		uid = getuid();
155  		gid = getgid();
156  		euid = geteuid();
157  		egid = getegid();
158  	}
159  
160  	if (mode != CURR) {
161  		if (!rflag) {
162  			uid = euid;
163  			gid = egid;
164  		}
165  		if (mode == USER)
166  			puid(uid);
167  		else if (mode == GROUP)
168  			pgid(gid);
169  		else if (mode == ALLGROUPS) {
170  			pgid(gid);
171  			if (user)
172  				i = getusergroups(groupmax, groupids, user,
173  				    prgid);
174  			else
175  				i = getgroups(groupmax, groupids);
176  			if (i == -1)
177  				perror("getgroups");
178  			else if (i > 0) {
179  				for (j = 0; j < i; ++j) {
180  					if ((gid = groupids[j]) == egid)
181  						continue;
182  					(void) putchar(' ');
183  					pgid(gid);
184  				}
185  			}
186  		}
187  		(void) putchar('\n');
188  	} else {
189  		prid(UID, uid);
190  		prid(GID, gid);
191  		if (uid != euid)
192  			prid(EUID, euid);
193  		if (gid != egid)
194  			prid(EGID, egid);
195  
196  		if (aflag) {
197  			if (user)
198  				i = getusergroups(groupmax, groupids, user,
199  				    prgid);
200  			else
201  				i = getgroups(groupmax, groupids);
202  			if (i == -1)
203  				perror("getgroups");
204  			else if (i > 0) {
205  				(void) printf(" groups=");
206  				for (idp = groupids; i--; idp++) {
207  					(void) printf("%u", *idp);
208  					if (gr = getgrgid(*idp))
209  						(void) printf("(%s)",
210  							gr->gr_name);
211  					if (i)
212  						(void) putchar(',');
213  				}
214  			}
215  		}
216  #ifdef XPG4
217  		/*
218  		 * POSIX requires us to show all supplementary groups
219  		 * groups other than the effective group already listed.
220  		 *
221  		 * This differs from -a above, because -a always shows
222  		 * all groups including the effective group in the group=
223  		 * line.
224  		 *
225  		 * It would be simpler if SunOS could just adopt this
226  		 * POSIX behavior, as it is so incredibly close to the
227  		 * the norm already.
228  		 *
229  		 * Then the magic -a flag could just indicate whether or
230  		 * not we are suppressing the effective group id.
231  		 */
232  		else {
233  			if (user)
234  				i = getusergroups(groupmax, groupids, user,
235  				    prgid);
236  			else
237  				i = getgroups(groupmax, groupids);
238  			if (i == -1)
239  				perror("getgroups");
240  			else if (i > 1) {
241  				(void) printf(" groups=");
242  				for (idp = groupids; i--; idp++) {
243  					if (*idp == egid)
244  						continue;
245  					(void) printf("%u", *idp);
246  					if (gr = getgrgid(*idp))
247  						(void) printf("(%s)",
248  							gr->gr_name);
249  					if (i)
250  						(void) putchar(',');
251  				}
252  			}
253  		}
254  #endif
255  		if (project_flag) {
256  			struct project proj;
257  			void *projbuf;
258  			projid_t curprojid = getprojid();
259  
260  			if ((projbuf = malloc(PROJECT_BUFSZ)) == NULL) {
261  				(void) fprintf(stderr, "unable to allocate "
262  				    "memory\n");
263  				return (2);
264  			}
265  
266  			if (user) {
267  				if (getdefaultproj(user, &proj, projbuf,
268  				    PROJECT_BUFSZ) != NULL)
269  					(void) printf(" projid=%d(%s)",
270  					    (int)proj.pj_projid, proj.pj_name);
271  				else
272  					/*
273  					 * This can only happen if project
274  					 * "default" has been removed from
275  					 * /etc/project file or the whole
276  					 * project database file was removed.
277  					 */
278  					(void) printf(" projid=(NONE)");
279  			} else {
280  				if (getprojbyid(curprojid, &proj, projbuf,
281  				    PROJECT_BUFSZ) == NULL)
282  					(void) printf(" projid=%d",
283  					    (int)curprojid);
284  				else
285  					(void) printf(" projid=%d(%s)",
286  					    (int)curprojid, proj.pj_name);
287  			}
288  			free(projbuf);
289  		}
290  		(void) putchar('\n');
291  	}
292  	return (0);
293  }
294  
295  static int
296  usage()
297  {
298  	(void) fprintf(stderr, gettext(
299  	    "Usage: id [-ap] [user]\n"
300  	    "       id -G [-n] [user]\n"
301  	    "       id -g [-nr] [user]\n"
302  	    "       id -u [-nr] [user]\n"));
303  	return (2);
304  }
305  
306  static void
307  puid(uid_t uid)
308  {
309  	struct passwd *pw;
310  
311  	if (nflag && (pw = getpwuid(uid)) != PWNULL)
312  		(void) printf("%s", pw->pw_name);
313  	else
314  		(void) printf("%u", uid);
315  }
316  
317  static void
318  pgid(gid_t gid)
319  {
320  	struct group *gr;
321  
322  	if (nflag && (gr = getgrgid(gid)) != GRNULL)
323  		(void) printf("%s", gr->gr_name);
324  	else
325  		(void) printf("%u", gid);
326  }
327  
328  static void
329  prid(TYPE how, uid_t id)
330  {
331  	char *s;
332  
333  	switch ((int)how) {
334  		case UID:
335  			s = "uid";
336  			break;
337  
338  		case EUID:
339  			s = " euid";
340  			break;
341  
342  		case GID:
343  			s = " gid";
344  			break;
345  
346  		case EGID:
347  			s = " egid";
348  			break;
349  
350  	}
351  	if (s != NULL)
352  		(void) printf("%s=", s);
353  	(void) printf("%u", id);
354  	switch ((int)how) {
355  	case UID:
356  	case EUID:
357  		{
358  			struct passwd *pwp;
359  
360  			if ((pwp = getpwuid(id)) != PWNULL)
361  				(void) printf("(%s)", pwp->pw_name);
362  
363  		}
364  		break;
365  	case GID:
366  	case EGID:
367  		{
368  			struct group *grp;
369  
370  			if ((grp = getgrgid(id)) != GRNULL)
371  				(void) printf("(%s)", grp->gr_name);
372  		}
373  		break;
374  	}
375  }
376  
377  /*
378   * Get the supplementary group affiliation for the user
379   */
380  static int getusergroups(gidsetsize, grouplist, user, prgid)
381  int	gidsetsize;
382  gid_t	*grouplist;
383  char	*user;
384  gid_t	prgid;
385  {
386  	struct group *group;
387  	char **gr_mem;
388  	int ngroups = 0;
389  
390  	setgrent();
391  	while ((ngroups < gidsetsize) && ((group = getgrent()) != NULL))
392  		for (gr_mem = group->gr_mem; *gr_mem; gr_mem++)
393  			if (strcmp(user, *gr_mem) == 0) {
394  				if (gidsetsize)
395  					grouplist[ngroups] = group->gr_gid;
396  				ngroups++;
397  			}
398  	endgrent();
399  	if (gidsetsize && !ngroups)
400  		grouplist[ngroups++] = prgid;
401  	return (ngroups);
402  }
403