xref: /illumos-gate/usr/src/cmd/ptools/pcred/pcred.c (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
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
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
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
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
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
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
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
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
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