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