Home | History | Annotate | Download | only in pcred
      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