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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.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 } 131 132 while (argc-- > 0) 133 rc += look(*argv++); 134 135 return (rc > 255 ? 255 : rc); 136 } 137 138 static void 139 credupdate(prcred_t *pcr) 140 { 141 if (uid != -1) 142 pcr->pr_euid = pcr->pr_ruid = pcr->pr_suid = uid; 143 if (gid != -1) 144 pcr->pr_egid = pcr->pr_rgid = pcr->pr_sgid = gid; 145 if (ngrp >= 0) { 146 147 pcr->pr_ngroups = ngrp; 148 149 (void) memcpy(pcr->pr_groups, groups, ngrp * sizeof (gid_t)); 150 } 151 } 152 153 static int 154 look(char *arg) 155 { 156 struct ps_prochandle *Pr; 157 static prcred_t *prcred = NULL; 158 int gcode; 159 160 procname = arg; /* for perr() */ 161 162 if (prcred == NULL) { 163 prcred = malloc(sizeof (prcred_t) + 164 (ngroups_max - 1) * sizeof (gid_t)); 165 if (prcred == NULL) { 166 (void) perr("malloc"); 167 exit(1); 168 } 169 } 170 171 if ((Pr = proc_arg_grab(arg, doset ? PR_ARG_PIDS : PR_ARG_ANY, 172 PGRAB_RETAIN | PGRAB_FORCE | (doset ? 0 : PGRAB_RDONLY) | 173 PGRAB_NOSTOP, &gcode)) == NULL) { 174 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 175 command, arg, Pgrab_error(gcode)); 176 return (1); 177 } 178 179 if (Pcred(Pr, prcred, ngroups_max) == -1) { 180 (void) perr("getcred"); 181 Prelease(Pr, 0); 182 return (1); 183 } 184 185 if (doset) { 186 credupdate(prcred); 187 if (Psetcred(Pr, prcred) != 0) { 188 (void) perr("setcred"); 189 Prelease(Pr, 0); 190 return (1); 191 } 192 Prelease(Pr, 0); 193 return (0); 194 } 195 196 if (Pstate(Pr) == PS_DEAD) 197 (void) printf("core of %d:\t", (int)Pstatus(Pr)->pr_pid); 198 else 199 (void) printf("%d:\t", (int)Pstatus(Pr)->pr_pid); 200 201 if (!all && 202 prcred->pr_euid == prcred->pr_ruid && 203 prcred->pr_ruid == prcred->pr_suid) 204 (void) printf("e/r/suid=%d ", 205 (int)prcred->pr_euid); 206 else 207 (void) printf("euid=%d ruid=%d suid=%d ", 208 (int)prcred->pr_euid, 209 (int)prcred->pr_ruid, 210 (int)prcred->pr_suid); 211 212 if (!all && 213 prcred->pr_egid == prcred->pr_rgid && 214 prcred->pr_rgid == prcred->pr_sgid) 215 (void) printf("e/r/sgid=%d\n", 216 (int)prcred->pr_egid); 217 else 218 (void) printf("egid=%d rgid=%d sgid=%d\n", 219 (int)prcred->pr_egid, 220 (int)prcred->pr_rgid, 221 (int)prcred->pr_sgid); 222 223 if (prcred->pr_ngroups != 0 && 224 (all || prcred->pr_ngroups != 1 || 225 prcred->pr_groups[0] != prcred->pr_rgid)) { 226 int i; 227 228 (void) printf("\tgroups:"); 229 for (i = 0; i < prcred->pr_ngroups; i++) 230 (void) printf(" %d", (int)prcred->pr_groups[i]); 231 (void) printf("\n"); 232 } 233 234 Prelease(Pr, 0); 235 return (0); 236 } 237 238 static int 239 perr(char *s) 240 { 241 if (s) 242 (void) fprintf(stderr, "%s: ", procname); 243 else 244 s = procname; 245 perror(s); 246 return (1); 247 } 248 249 static void 250 usage(void) 251 { 252 (void) fprintf(stderr, "usage:\t%s [-a] { pid | core } ...\n" 253 "\t%s [-u user] [-g group] [-G groups] pid ...\n" 254 "\t%s -l login pid ...\n" 255 " (report or modify process credentials)\n", 256 command, command, command); 257 exit(2); 258 } 259 260 261 static id_t 262 str2id(const char *str) 263 { 264 long res; 265 char *p; 266 267 res = strtol(str, &p, 0); 268 if (p == str || *p != '\0' || res < 0) 269 return (-1); 270 else 271 return ((id_t)res); 272 } 273 274 static gid_t 275 str2gid(const char *grnam) 276 { 277 struct group *grp = getgrnam(grnam); 278 gid_t res; 279 280 if (grp == NULL) { 281 res = str2id(grnam); 282 if (res < 0) { 283 (void) fprintf(stderr, "%s: %s: unknown group" 284 " or bad gid\n", 285 command, grnam); 286 exit(1); 287 } 288 } else { 289 res = grp->gr_gid; 290 } 291 return (res); 292 } 293 294 static void 295 initcred(void) 296 { 297 struct passwd *pwd; 298 299 if ((groups = malloc(ngroups_max * sizeof (gid_t))) == NULL) { 300 (void) perr("malloc"); 301 exit(1); 302 } 303 304 if (login != NULL) { 305 pwd = getpwnam(login); 306 307 if (pwd == NULL) { 308 (void) fprintf(stderr, "%s: %s: unknown user\n", 309 command, login); 310 exit(1); 311 } 312 uid = pwd->pw_uid; 313 gid = pwd->pw_gid; 314 315 groups[0] = gid; 316 317 ngrp = _getgroupsbymember(login, groups, (int)ngroups_max, 1); 318 } 319 320 if (user != NULL) { 321 pwd = getpwnam(user); 322 if (pwd == NULL) { 323 uid = str2id(user); 324 if (uid < 0) { 325 (void) fprintf(stderr, "%s: %s: unknown user" 326 " or bad uid\n", 327 command, user); 328 exit(1); 329 } 330 } else { 331 uid = pwd->pw_uid; 332 } 333 } 334 335 if (group != NULL) 336 gid = str2gid(group); 337 338 if (grplst != NULL) { 339 char *cgrp; 340 341 ngrp = 0; 342 343 while ((cgrp = strtok(grplst, ",")) != NULL) { 344 345 if (ngrp >= ngroups_max) { 346 (void) fprintf(stderr, "%s: Too many groups\n", 347 command); 348 exit(1); 349 } 350 groups[ngrp++] = str2gid(cgrp); 351 352 /* For iterations of strtok */ 353 grplst = NULL; 354 } 355 } 356 } 357