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