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 #include <errno.h>
29 #include <stdio.h>
30 #include <stdio_ext.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <limits.h>
36 #include <sys/types.h>
37 #include <pwd.h>
38 #include <grp.h>
39 #include <libproc.h>
40
41 extern int _getgroupsbymember(const char *, gid_t[], int, int);
42
43 static int look(char *);
44 static int perr(char *);
45
46 static void usage(void);
47 static void initcred(void);
48
49 static char *command;
50 static char *procname;
51
52 static char *user;
53 static char *group;
54 static char *grplst;
55 static char *login;
56
57 static boolean_t all = B_FALSE;
58 static boolean_t doset = B_FALSE;
59 static int ngrp = -1;
60 static gid_t *groups;
61 static long ngroups_max;
62
63 static uid_t uid = (uid_t)-1;
64 static gid_t gid = (gid_t)-1;
65
66 int
main(int argc,char ** argv)67 main(int argc, char **argv)
68 {
69 int rc = 0;
70 int c;
71 struct rlimit rlim;
72
73 if ((command = strrchr(argv[0], '/')) != NULL)
74 command++;
75 else
76 command = argv[0];
77
78 if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0)
79 return (perr("sysconf(_SC_NGROUPS_MAX)"));
80
81 opterr = 0;
82
83 while ((c = getopt(argc, argv, "au:g:l:G:")) != EOF) {
84 switch (c) {
85 case 'a':
86 all = B_TRUE;
87 break;
88 case 'u':
89 user = optarg;
90 doset = B_TRUE;
91 break;
92 case 'g':
93 group = optarg;
94 doset = B_TRUE;
95 break;
96 case 'G':
97 grplst = optarg;
98 doset = B_TRUE;
99 break;
100 case 'l':
101 login = optarg;
102 doset = B_TRUE;
103 break;
104 default:
105 usage();
106 /*NOTREACHED*/
107 }
108 }
109 if (login != NULL && (user != NULL || group != NULL || grplst != NULL))
110 usage();
111
112 if (all && doset)
113 usage();
114
115 argc -= optind;
116 argv += optind;
117
118 if (argc == 0)
119 usage();
120
121 if (doset)
122 initcred();
123
124 /*
125 * Make sure we'll have enough file descriptors to handle a target
126 * that has many many mappings.
127 */
128 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
129 rlim.rlim_cur = rlim.rlim_max;
130 (void) setrlimit(RLIMIT_NOFILE, &rlim);
131 (void) enable_extended_FILE_stdio(-1, -1);
132 }
133
134 while (argc-- > 0)
135 rc += look(*argv++);
136
137 return (rc > 255 ? 255 : rc);
138 }
139
140 static void
credupdate(prcred_t * pcr)141 credupdate(prcred_t *pcr)
142 {
143 if (uid != (uid_t)-1)
144 pcr->pr_euid = pcr->pr_ruid = pcr->pr_suid = uid;
145 if (gid != (gid_t)-1)
146 pcr->pr_egid = pcr->pr_rgid = pcr->pr_sgid = gid;
147 if (ngrp >= 0) {
148
149 pcr->pr_ngroups = ngrp;
150
151 (void) memcpy(pcr->pr_groups, groups, ngrp * sizeof (gid_t));
152 }
153 }
154
155 static int
look(char * arg)156 look(char *arg)
157 {
158 struct ps_prochandle *Pr;
159 static prcred_t *prcred = NULL;
160 int gcode;
161
162 procname = arg; /* for perr() */
163
164 if (prcred == NULL) {
165 prcred = malloc(sizeof (prcred_t) +
166 (ngroups_max - 1) * sizeof (gid_t));
167 if (prcred == NULL) {
168 (void) perr("malloc");
169 exit(1);
170 }
171 }
172
173 if ((Pr = proc_arg_grab(arg, doset ? PR_ARG_PIDS : PR_ARG_ANY,
174 PGRAB_RETAIN | PGRAB_FORCE | (doset ? 0 : PGRAB_RDONLY) |
175 PGRAB_NOSTOP, &gcode)) == NULL) {
176 (void) fprintf(stderr, "%s: cannot examine %s: %s\n",
177 command, arg, Pgrab_error(gcode));
178 return (1);
179 }
180
181 if (Pcred(Pr, prcred, ngroups_max) == -1) {
182 (void) perr("getcred");
183 Prelease(Pr, 0);
184 return (1);
185 }
186
187 if (doset) {
188 credupdate(prcred);
189 if (Psetcred(Pr, prcred) != 0) {
190 (void) perr("setcred");
191 Prelease(Pr, 0);
192 return (1);
193 }
194 Prelease(Pr, 0);
195 return (0);
196 }
197
198 if (Pstate(Pr) == PS_DEAD)
199 (void) printf("core of %d:\t", (int)Pstatus(Pr)->pr_pid);
200 else
201 (void) printf("%d:\t", (int)Pstatus(Pr)->pr_pid);
202
203 if (!all &&
204 prcred->pr_euid == prcred->pr_ruid &&
205 prcred->pr_ruid == prcred->pr_suid)
206 (void) printf("e/r/suid=%u ", prcred->pr_euid);
207 else
208 (void) printf("euid=%u ruid=%u suid=%u ",
209 prcred->pr_euid, prcred->pr_ruid, prcred->pr_suid);
210
211 if (!all &&
212 prcred->pr_egid == prcred->pr_rgid &&
213 prcred->pr_rgid == prcred->pr_sgid)
214 (void) printf("e/r/sgid=%u\n", prcred->pr_egid);
215 else
216 (void) printf("egid=%u rgid=%u sgid=%u\n",
217 prcred->pr_egid, prcred->pr_rgid, prcred->pr_sgid);
218
219 if (prcred->pr_ngroups != 0 &&
220 (all || prcred->pr_ngroups != 1 ||
221 prcred->pr_groups[0] != prcred->pr_rgid)) {
222 int i;
223
224 (void) printf("\tgroups:");
225 for (i = 0; i < prcred->pr_ngroups; i++)
226 (void) printf(" %u", prcred->pr_groups[i]);
227 (void) printf("\n");
228 }
229
230 Prelease(Pr, 0);
231 return (0);
232 }
233
234 static int
perr(char * s)235 perr(char *s)
236 {
237 if (s)
238 (void) fprintf(stderr, "%s: ", procname);
239 else
240 s = procname;
241 perror(s);
242 return (1);
243 }
244
245 static void
usage(void)246 usage(void)
247 {
248 (void) fprintf(stderr, "usage:\t%s [-a] { pid | core } ...\n"
249 "\t%s [-u user] [-g group] [-G groups] pid ...\n"
250 "\t%s -l login pid ...\n"
251 " (report or modify process credentials)\n",
252 command, command, command);
253 exit(2);
254 }
255
256
257 static uint32_t
str2id(const char * str)258 str2id(const char *str)
259 {
260 unsigned long res;
261 char *p;
262
263 errno = 0;
264 res = strtoul(str, &p, 0);
265 if (p == str || *p != '\0' || errno != 0)
266 return ((uint32_t)-1);
267 else
268 return ((uint32_t)res);
269 }
270
271 static gid_t
str2gid(const char * grnam)272 str2gid(const char *grnam)
273 {
274 struct group *grp = getgrnam(grnam);
275 gid_t res;
276
277 if (grp == NULL) {
278 res = (gid_t)str2id(grnam);
279 if (res == (gid_t)-1) {
280 (void) fprintf(stderr, "%s: %s: unknown group"
281 " or bad gid\n",
282 command, grnam);
283 exit(1);
284 }
285 } else {
286 res = grp->gr_gid;
287 }
288 return (res);
289 }
290
291 static void
initcred(void)292 initcred(void)
293 {
294 struct passwd *pwd;
295
296 if ((groups = malloc(ngroups_max * sizeof (gid_t))) == NULL) {
297 (void) perr("malloc");
298 exit(1);
299 }
300
301 if (login != NULL) {
302 pwd = getpwnam(login);
303
304 if (pwd == NULL) {
305 (void) fprintf(stderr, "%s: %s: unknown user\n",
306 command, login);
307 exit(1);
308 }
309 uid = pwd->pw_uid;
310 gid = pwd->pw_gid;
311
312 groups[0] = gid;
313
314 ngrp = _getgroupsbymember(login, groups, (int)ngroups_max, 1);
315 }
316
317 if (user != NULL) {
318 pwd = getpwnam(user);
319 if (pwd == NULL) {
320 uid = (uid_t)str2id(user);
321 if (uid == (uid_t)-1) {
322 (void) fprintf(stderr, "%s: %s: unknown user"
323 " or bad uid\n",
324 command, user);
325 exit(1);
326 }
327 } else {
328 uid = pwd->pw_uid;
329 }
330 }
331
332 if (group != NULL)
333 gid = str2gid(group);
334
335 if (grplst != NULL) {
336 char *cgrp;
337
338 ngrp = 0;
339
340 while ((cgrp = strtok(grplst, ",")) != NULL) {
341
342 if (ngrp >= ngroups_max) {
343 (void) fprintf(stderr, "%s: Too many groups\n",
344 command);
345 exit(1);
346 }
347 groups[ngrp++] = str2gid(cgrp);
348
349 /* For iterations of strtok */
350 grplst = NULL;
351 }
352 }
353 }
354