1/*
2 * id - POSIX.2 user identity
3 *
4 * (INCOMPLETE -- supplementary groups for other users not yet done)
5 *
6 * usage: id [-Ggu] [-nr] [user]
7 *
8 * The default output format looks something like:
9 *	uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname)
10 */
11
12#include <config.h>
13#include <stdio.h>
14#include "bashtypes.h"
15#include <pwd.h>
16#include <grp.h>
17#include "bashansi.h"
18
19#ifdef HAVE_LIMITS_H
20#  include <limits.h>
21#else
22#  include <sys/param.h>
23#endif
24
25#if !defined (HAVE_GETPW_DECLS)
26extern struct passwd *getpwuid ();
27#endif
28extern struct group *getgrgid ();
29
30#include "shell.h"
31#include "builtins.h"
32#include "stdc.h"
33#include "common.h"
34#include "bashgetopt.h"
35
36#define ID_ALLGROUPS	0x001		/* -G */
37#define ID_GIDONLY	0x002		/* -g */
38#define ID_USENAME	0x004		/* -n */
39#define ID_USEREAL	0x008		/* -r */
40#define ID_USERONLY	0x010		/* -u */
41
42#define ID_FLAGSET(s)	((id_flags & (s)) != 0)
43
44static int id_flags;
45
46static uid_t ruid, euid;
47static gid_t rgid, egid;
48
49static char *id_user;
50
51static int inituser ();
52
53static int id_pruser ();
54static int id_prgrp ();
55static int id_prgroups ();
56static int id_prall ();
57
58int
59id_builtin (list)
60     WORD_LIST *list;
61{
62  int opt;
63  char *user;
64
65  id_flags = 0;
66  reset_internal_getopt ();
67  while ((opt = internal_getopt (list, "Ggnru")) != -1)
68    {
69      switch (opt)
70	{
71	case 'G': id_flags |= ID_ALLGROUPS; break;
72	case 'g': id_flags |= ID_GIDONLY; break;
73	case 'n': id_flags |= ID_USENAME; break;
74	case 'r': id_flags |= ID_USEREAL; break;
75	case 'u': id_flags |= ID_USERONLY; break;
76	default:
77	  builtin_usage ();
78	  return (EX_USAGE);
79	}
80    }
81  list = loptend;
82
83  user = list ? list->word->word : (char *)NULL;
84
85  /* Check for some invalid option combinations */
86  opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY);
87  if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0)))
88    {
89      builtin_usage ();
90      return (EX_USAGE);
91    }
92
93  if (list && list->next)
94    {
95      builtin_usage ();
96      return (EX_USAGE);
97    }
98
99  if (inituser (user) < 0)
100    return (EXECUTION_FAILURE);
101
102  opt = 0;
103  if (id_flags & ID_USERONLY)
104    opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid);
105  else if (id_flags & ID_GIDONLY)
106    opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid);
107  else if (id_flags & ID_ALLGROUPS)
108    opt += id_prgroups (user);
109  else
110    opt += id_prall (user);
111  putchar ('\n');
112  fflush (stdout);
113
114  return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
115}
116
117static int
118inituser (uname)
119     char *uname;
120{
121  struct passwd *pwd;
122
123  if (uname)
124    {
125      pwd = getpwnam (uname);
126      if (pwd == 0)
127	{
128	  builtin_error ("%s: no such user", uname);
129	  return -1;
130	}
131      ruid = euid = pwd->pw_uid;
132      rgid = egid = pwd->pw_gid;
133    }
134  else
135    {
136      ruid = current_user.uid;
137      euid = current_user.euid;
138      rgid = current_user.gid;
139      egid = current_user.egid;
140    }
141  return 0;
142}
143
144/* Print the name or value of user ID UID. */
145static int
146id_pruser (uid)
147     int uid;
148{
149  struct passwd *pwd = NULL;
150  int r;
151
152  r = 0;
153  if (id_flags & ID_USENAME)
154    {
155      pwd = getpwuid (uid);
156      if (pwd == NULL)
157        r = 1;
158    }
159  if (pwd)
160    printf ("%s", pwd->pw_name);
161  else
162    printf ("%u", (unsigned) uid);
163
164  return r;
165}
166
167/* Print the name or value of group ID GID. */
168
169static int
170id_prgrp (gid)
171     int gid;
172{
173  struct group *grp = NULL;
174  int r;
175
176  r = 0;
177  if (id_flags & ID_USENAME)
178    {
179      grp = getgrgid (gid);
180      if (grp == NULL)
181	r = 1;
182    }
183
184  if (grp)
185    printf ("%s", grp->gr_name);
186  else
187    printf ("%u", (unsigned) gid);
188
189  return r;
190}
191
192static int
193id_prgroups (uname)
194     char *uname;
195{
196  int *glist, ng, i, r;
197
198  r = 0;
199  id_prgrp (rgid);
200  if (egid != rgid)
201    {
202      putchar (' ');
203      id_prgrp (egid);
204    }
205
206  if (uname)
207    {
208      builtin_error ("supplementary groups for other users not yet implemented");
209      glist = (int *)NULL;
210      ng = 0;
211      r = 1;
212    }
213  else
214    glist = get_group_array (&ng);
215
216  for (i = 0; i < ng; i++)
217    if (glist[i] != rgid && glist[i] != egid)
218      {
219	putchar (' ');
220	id_prgrp (glist[i]);
221      }
222
223  return r;
224}
225
226static int
227id_prall (uname)
228     char *uname;
229{
230  int r, i, ng, *glist;
231  struct passwd *pwd;
232  struct group *grp;
233
234  r = 0;
235  printf ("uid=%u", (unsigned) ruid);
236  pwd = getpwuid (ruid);
237  if (pwd == NULL)
238    r = 1;
239  else
240    printf ("(%s)", pwd->pw_name);
241
242  printf (" gid=%u", (unsigned) rgid);
243  grp = getgrgid (rgid);
244  if (grp == NULL)
245    r = 1;
246  else
247    printf ("(%s)", grp->gr_name);
248
249  if (euid != ruid)
250    {
251      printf (" euid=%u", (unsigned) euid);
252      pwd = getpwuid (euid);
253      if (pwd == NULL)
254	r = 1;
255      else
256	printf ("(%s)", pwd->pw_name);
257    }
258
259  if (egid != rgid)
260    {
261      printf (" egid=%u", (unsigned) egid);
262      grp = getgrgid (egid);
263      if (grp == NULL)
264	r = 1;
265      else
266	printf ("(%s)", grp->gr_name);
267    }
268
269  if (uname)
270    {
271      builtin_error ("supplementary groups for other users not yet implemented");
272      glist = (int *)NULL;
273      ng = 0;
274      r = 1;
275    }
276  else
277    glist = get_group_array (&ng);
278
279  if (ng > 0)
280    printf (" groups=");
281  for (i = 0; i < ng; i++)
282    {
283      if (i > 0)
284	printf (", ");
285      printf ("%u", (unsigned) glist[i]);
286      grp = getgrgid (glist[i]);
287      if (grp == NULL)
288	r = 1;
289      else
290	printf ("(%s)", grp->gr_name);
291    }
292
293  return r;
294}
295
296char *id_doc[] = {
297	"return information about user identity",
298	(char *)NULL
299};
300
301struct builtin id_struct = {
302	"id",
303	id_builtin,
304	BUILTIN_ENABLED,
305	id_doc,
306	"id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]",
307	0
308};
309