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