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 #include <errno.h> 27 #include <stdio.h> 28 #include <stdio_ext.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <string.h> 33 #include <limits.h> 34 #include <sys/types.h> 35 #include <pwd.h> 36 #include <grp.h> 37 #include <libproc.h> 38 39 extern int _getgroupsbymember(const char *, gid_t[], int, int); 40 41 static int look(char *); 42 static int perr(char *); 43 44 static void usage(void); 45 static void initcred(void); 46 47 static char *command; 48 static char *procname; 49 50 static char *user; 51 static char *group; 52 static char *grplst; 53 static char *login; 54 55 static boolean_t all = B_FALSE; 56 static boolean_t doset = B_FALSE; 57 static int ngrp = -1; 58 static gid_t *groups; 59 static long ngroups_max; 60 61 static uid_t uid = (uid_t)-1; 62 static gid_t gid = (gid_t)-1; 63 64 int 65 main(int argc, char **argv) 66 { 67 int rc = 0; 68 int c; 69 struct rlimit rlim; 70 71 if ((command = strrchr(argv[0], '/')) != NULL) 72 command++; 73 else 74 command = argv[0]; 75 76 if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0) 77 return (perr("sysconf(_SC_NGROUPS_MAX)")); 78 79 opterr = 0; 80 81 while ((c = getopt(argc, argv, "au:g:l:G:")) != EOF) { 82 switch (c) { 83 case 'a': 84 all = B_TRUE; 85 break; 86 case 'u': 87 user = optarg; 88 doset = B_TRUE; 89 break; 90 case 'g': 91 group = optarg; 92 doset = B_TRUE; 93 break; 94 case 'G': 95 grplst = optarg; 96 doset = B_TRUE; 97 break; 98 case 'l': 99 login = optarg; 100 doset = B_TRUE; 101 break; 102 default: 103 usage(); 104 /*NOTREACHED*/ 105 } 106 } 107 if (login != NULL && (user != NULL || group != NULL || grplst != NULL)) 108 usage(); 109 110 if (all && doset) 111 usage(); 112 113 argc -= optind; 114 argv += optind; 115 116 if (argc == 0) 117 usage(); 118 119 if (doset) 120 initcred(); 121 122 /* 123 * Make sure we'll have enough file descriptors to handle a target 124 * that has many many mappings. 125 */ 126 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 127 rlim.rlim_cur = rlim.rlim_max; 128 (void) setrlimit(RLIMIT_NOFILE, &rlim); 129 (void) enable_extended_FILE_stdio(-1, -1); 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 != (uid_t)-1) 142 pcr->pr_euid = pcr->pr_ruid = pcr->pr_suid = uid; 143 if (gid != (gid_t)-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=%u ", prcred->pr_euid); 205 else 206 (void) printf("euid=%u ruid=%u suid=%u ", 207 prcred->pr_euid, prcred->pr_ruid, prcred->pr_suid); 208 209 if (!all && 210 prcred->pr_egid == prcred->pr_rgid && 211 prcred->pr_rgid == prcred->pr_sgid) 212 (void) printf("e/r/sgid=%u\n", prcred->pr_egid); 213 else 214 (void) printf("egid=%u rgid=%u sgid=%u\n", 215 prcred->pr_egid, prcred->pr_rgid, prcred->pr_sgid); 216 217 if (prcred->pr_ngroups != 0 && 218 (all || prcred->pr_ngroups != 1 || 219 prcred->pr_groups[0] != prcred->pr_rgid)) { 220 int i; 221 222 (void) printf("\tgroups:"); 223 for (i = 0; i < prcred->pr_ngroups; i++) 224 (void) printf(" %u", prcred->pr_groups[i]); 225 (void) printf("\n"); 226 } 227 228 Prelease(Pr, 0); 229 return (0); 230 } 231 232 static int 233 perr(char *s) 234 { 235 if (s) 236 (void) fprintf(stderr, "%s: ", procname); 237 else 238 s = procname; 239 perror(s); 240 return (1); 241 } 242 243 static void 244 usage(void) 245 { 246 (void) fprintf(stderr, "usage:\t%s [-a] { pid | core } ...\n" 247 "\t%s [-u user] [-g group] [-G groups] pid ...\n" 248 "\t%s -l login pid ...\n" 249 " (report or modify process credentials)\n", 250 command, command, command); 251 exit(2); 252 } 253 254 255 static uint32_t 256 str2id(const char *str) 257 { 258 unsigned long res; 259 char *p; 260 261 errno = 0; 262 res = strtoul(str, &p, 0); 263 if (p == str || *p != '\0' || errno != 0) 264 return ((uint32_t)-1); 265 else 266 return ((uint32_t)res); 267 } 268 269 static gid_t 270 str2gid(const char *grnam) 271 { 272 struct group *grp = getgrnam(grnam); 273 gid_t res; 274 275 if (grp == NULL) { 276 res = (gid_t)str2id(grnam); 277 if (res == (gid_t)-1) { 278 (void) fprintf(stderr, "%s: %s: unknown group" 279 " or bad gid\n", 280 command, grnam); 281 exit(1); 282 } 283 } else { 284 res = grp->gr_gid; 285 } 286 return (res); 287 } 288 289 static void 290 initcred(void) 291 { 292 struct passwd *pwd; 293 294 if ((groups = malloc(ngroups_max * sizeof (gid_t))) == NULL) { 295 (void) perr("malloc"); 296 exit(1); 297 } 298 299 if (login != NULL) { 300 pwd = getpwnam(login); 301 302 if (pwd == NULL) { 303 (void) fprintf(stderr, "%s: %s: unknown user\n", 304 command, login); 305 exit(1); 306 } 307 uid = pwd->pw_uid; 308 gid = pwd->pw_gid; 309 310 groups[0] = gid; 311 312 ngrp = _getgroupsbymember(login, groups, (int)ngroups_max, 1); 313 } 314 315 if (user != NULL) { 316 pwd = getpwnam(user); 317 if (pwd == NULL) { 318 uid = (uid_t)str2id(user); 319 if (uid == (uid_t)-1) { 320 (void) fprintf(stderr, "%s: %s: unknown user" 321 " or bad uid\n", 322 command, user); 323 exit(1); 324 } 325 } else { 326 uid = pwd->pw_uid; 327 } 328 } 329 330 if (group != NULL) 331 gid = str2gid(group); 332 333 if (grplst != NULL) { 334 char *cgrp; 335 336 ngrp = 0; 337 338 while ((cgrp = strtok(grplst, ",")) != NULL) { 339 340 if (ngrp >= ngroups_max) { 341 (void) fprintf(stderr, "%s: Too many groups\n", 342 command); 343 exit(1); 344 } 345 groups[ngrp++] = str2gid(cgrp); 346 347 /* For iterations of strtok */ 348 grplst = NULL; 349 } 350 } 351 } 352