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