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