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