dd: clarify meaning of multiplication factors; put xM in order
[platform/upstream/coreutils.git] / src / id.c
1 /* id -- print real and effective UIDs and GIDs
2    Copyright (C) 1989-2008 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Arnold Robbins.
18    Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <getopt.h>
26 #include <selinux/selinux.h>
27
28 #include "system.h"
29 #include "error.h"
30 #include "mgetgroups.h"
31 #include "quote.h"
32 #include "group-list.h"
33
34 /* The official name of this program (e.g., no `g' prefix).  */
35 #define PROGRAM_NAME "id"
36
37 #define AUTHORS \
38   proper_name ("Arnold Robbins"), \
39   proper_name ("David MacKenzie")
40
41 /* If nonzero, output only the SELinux context. -Z */
42 static int just_context = 0;
43
44 static void print_user (uid_t uid);
45 static void print_full_info (const char *username);
46
47 /* If true, output user/group name instead of ID number. -n */
48 static bool use_name = false;
49
50 /* The real and effective IDs of the user to print. */
51 static uid_t ruid, euid;
52 static gid_t rgid, egid;
53
54 /* True unless errors have been encountered.  */
55 static bool ok = true;
56
57 /* The SELinux context.  Start with a known invalid value so print_full_info
58    knows when `context' has not been set to a meaningful value.  */
59 static security_context_t context = NULL;
60
61 static struct option const longopts[] =
62 {
63   {"context", no_argument, NULL, 'Z'},
64   {"group", no_argument, NULL, 'g'},
65   {"groups", no_argument, NULL, 'G'},
66   {"name", no_argument, NULL, 'n'},
67   {"real", no_argument, NULL, 'r'},
68   {"user", no_argument, NULL, 'u'},
69   {GETOPT_HELP_OPTION_DECL},
70   {GETOPT_VERSION_OPTION_DECL},
71   {NULL, 0, NULL, 0}
72 };
73
74 void
75 usage (int status)
76 {
77   if (status != EXIT_SUCCESS)
78     fprintf (stderr, _("Try `%s --help' for more information.\n"),
79              program_name);
80   else
81     {
82       printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
83       fputs (_("\
84 Print information for USERNAME, or the current user.\n\
85 \n\
86   -a              ignore, for compatibility with other versions\n\
87   -Z, --context   print only the security context of the current user\n\
88   -g, --group     print only the effective group ID\n\
89   -G, --groups    print all group IDs\n\
90   -n, --name      print a name instead of a number, for -ugG\n\
91   -r, --real      print the real ID instead of the effective ID, with -ugG\n\
92   -u, --user      print only the effective user ID\n\
93 "), stdout);
94       fputs (HELP_OPTION_DESCRIPTION, stdout);
95       fputs (VERSION_OPTION_DESCRIPTION, stdout);
96       fputs (_("\
97 \n\
98 Without any OPTION, print some useful set of identified information.\n\
99 "), stdout);
100       emit_bug_reporting_address ();
101     }
102   exit (status);
103 }
104
105 int
106 main (int argc, char **argv)
107 {
108   int optc;
109   int selinux_enabled = (is_selinux_enabled () > 0);
110
111   /* If true, output the list of all group IDs. -G */
112   bool just_group_list = false;
113   /* If true, output only the group ID(s). -g */
114   bool just_group = false;
115   /* If true, output real UID/GID instead of default effective UID/GID. -r */
116   bool use_real = false;
117   /* If true, output only the user ID(s). -u */
118   bool just_user = false;
119
120   initialize_main (&argc, &argv);
121   set_program_name (argv[0]);
122   setlocale (LC_ALL, "");
123   bindtextdomain (PACKAGE, LOCALEDIR);
124   textdomain (PACKAGE);
125
126   atexit (close_stdout);
127
128   while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1)
129     {
130       switch (optc)
131         {
132         case 'a':
133           /* Ignore -a, for compatibility with SVR4.  */
134           break;
135
136         case 'Z':
137           /* politely decline if we're not on a selinux-enabled kernel. */
138           if (!selinux_enabled)
139             error (EXIT_FAILURE, 0,
140                    _("--context (-Z) works only on an SELinux-enabled kernel"));
141           just_context = 1;
142           break;
143
144         case 'g':
145           just_group = true;
146           break;
147         case 'n':
148           use_name = true;
149           break;
150         case 'r':
151           use_real = true;
152           break;
153         case 'u':
154           just_user = true;
155           break;
156         case 'G':
157           just_group_list = true;
158           break;
159         case_GETOPT_HELP_CHAR;
160         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
161         default:
162           usage (EXIT_FAILURE);
163         }
164     }
165
166   if (1 < argc - optind)
167     {
168       error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
169       usage (EXIT_FAILURE);
170     }
171
172   if (argc - optind == 1 && just_context)
173     error (EXIT_FAILURE, 0,
174            _("cannot print security context when user specified"));
175
176   if (just_context && !selinux_enabled)
177     error (EXIT_FAILURE, 0, _("\
178 cannot display context when selinux not enabled or when displaying the id\n\
179 of a different user"));
180
181   /* If we are on a selinux-enabled kernel and no user is specified,
182      get our context. Otherwise, leave the context variable alone -
183      it has been initialized known invalid value and will be not
184      displayed in print_full_info() */
185   if (selinux_enabled && argc == optind)
186     {
187       if (getcon (&context) && just_context)
188         error (EXIT_FAILURE, 0, _("can't get process context"));
189     }
190
191   if (just_user + just_group + just_group_list + just_context > 1)
192     error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice"));
193
194   if (just_user + just_group + just_group_list == 0 && (use_real | use_name))
195     error (EXIT_FAILURE, 0,
196            _("cannot print only names or real IDs in default format"));
197
198   if (argc - optind == 1)
199     {
200       struct passwd *pwd = getpwnam (argv[optind]);
201       if (pwd == NULL)
202         error (EXIT_FAILURE, 0, _("%s: No such user"), argv[optind]);
203       ruid = euid = pwd->pw_uid;
204       rgid = egid = pwd->pw_gid;
205     }
206   else
207     {
208       euid = geteuid ();
209       ruid = getuid ();
210       egid = getegid ();
211       rgid = getgid ();
212     }
213
214   if (just_user)
215     {
216       print_user (use_real ? ruid : euid);
217     }
218   else if (just_group)
219     {
220       if (!print_group (use_real ? rgid : egid, use_name))
221         ok = false;
222     }
223   else if (just_group_list)
224     {
225       if (!print_group_list (argv[optind], ruid, rgid, egid, use_name))
226         ok = false;
227     }
228   else if (just_context)
229     {
230       fputs (context, stdout);
231     }
232   else
233     {
234       print_full_info (argv[optind]);
235     }
236   putchar ('\n');
237
238   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
239 }
240
241 /* Print the name or value of user ID UID. */
242
243 static void
244 print_user (uid_t uid)
245 {
246   struct passwd *pwd = NULL;
247
248   if (use_name)
249     {
250       pwd = getpwuid (uid);
251       if (pwd == NULL)
252         {
253           error (0, 0, _("cannot find name for user ID %lu"),
254                  (unsigned long int) uid);
255           ok = false;
256         }
257     }
258
259   if (pwd == NULL)
260     printf ("%lu", (unsigned long int) uid);
261   else
262     printf ("%s", pwd->pw_name);
263 }
264
265 /* Print all of the info about the user's user and group IDs. */
266
267 static void
268 print_full_info (const char *username)
269 {
270   struct passwd *pwd;
271   struct group *grp;
272
273   printf ("uid=%lu", (unsigned long int) ruid);
274   pwd = getpwuid (ruid);
275   if (pwd)
276     printf ("(%s)", pwd->pw_name);
277
278   printf (" gid=%lu", (unsigned long int) rgid);
279   grp = getgrgid (rgid);
280   if (grp)
281     printf ("(%s)", grp->gr_name);
282
283   if (euid != ruid)
284     {
285       printf (" euid=%lu", (unsigned long int) euid);
286       pwd = getpwuid (euid);
287       if (pwd)
288         printf ("(%s)", pwd->pw_name);
289     }
290
291   if (egid != rgid)
292     {
293       printf (" egid=%lu", (unsigned long int) egid);
294       grp = getgrgid (egid);
295       if (grp)
296         printf ("(%s)", grp->gr_name);
297     }
298
299 #if HAVE_GETGROUPS
300   {
301     GETGROUPS_T *groups;
302     size_t i;
303
304     int n_groups = mgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
305                                &groups);
306     if (n_groups < 0)
307       {
308         if (username)
309           {
310             error (0, errno, _("failed to get groups for user %s"),
311                    quote (username));
312           }
313         else
314           {
315             error (0, errno, _("failed to get groups for the current process"));
316           }
317         ok = false;
318         return;
319       }
320
321     if (n_groups > 0)
322       fputs (_(" groups="), stdout);
323     for (i = 0; i < n_groups; i++)
324       {
325         if (i > 0)
326           putchar (',');
327         printf ("%lu", (unsigned long int) groups[i]);
328         grp = getgrgid (groups[i]);
329         if (grp)
330           printf ("(%s)", grp->gr_name);
331       }
332     free (groups);
333   }
334 #endif /* HAVE_GETGROUPS */
335   if (context != NULL)
336     printf (" context=%s", context);
337 }