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