1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/mac.h> 34 35 #ifdef USE_BSM_AUDIT 36 #include <bsm/audit.h> 37 #endif 38 39 #include <err.h> 40 #include <errno.h> 41 #include <grp.h> 42 #include <pwd.h> 43 #include <stdbool.h> 44 #include <stdint.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 static void id_print(struct passwd *); 51 static void pline(struct passwd *); 52 static void pretty(struct passwd *); 53 #ifdef USE_BSM_AUDIT 54 static void auditid(void); 55 #endif 56 static void group(struct passwd *, bool); 57 static void maclabel(void); 58 static void dir(struct passwd *); 59 static void shell(struct passwd *); 60 static void usage(void); 61 static struct passwd *who(char *); 62 63 static bool isgroups, iswhoami; 64 65 int 66 main(int argc, char *argv[]) 67 { 68 struct group *gr; 69 struct passwd *pw; 70 bool Aflag, Gflag, Mflag, Pflag; 71 bool cflag, dflag, gflag, nflag, pflag, rflag, sflag, uflag; 72 int ch, combo, error, id; 73 const char *myname, *optstr; 74 char loginclass[MAXLOGNAME]; 75 76 Aflag = Gflag = Mflag = Pflag = false; 77 cflag = dflag = gflag = nflag = pflag = rflag = sflag = uflag = false; 78 79 myname = getprogname(); 80 optstr = "AGMPacdgnprsu"; 81 if (strcmp(myname, "groups") == 0) { 82 isgroups = true; 83 optstr = ""; 84 Gflag = nflag = true; 85 } 86 else if (strcmp(myname, "whoami") == 0) { 87 iswhoami = true; 88 optstr = ""; 89 uflag = nflag = true; 90 } 91 92 while ((ch = getopt(argc, argv, optstr)) != -1) { 93 switch(ch) { 94 #ifdef USE_BSM_AUDIT 95 case 'A': 96 Aflag = true; 97 break; 98 #endif 99 case 'G': 100 Gflag = true; 101 break; 102 case 'M': 103 Mflag = true; 104 break; 105 case 'P': 106 Pflag = true; 107 break; 108 case 'a': 109 break; 110 case 'c': 111 cflag = true; 112 break; 113 case 'd': 114 dflag = true; 115 break; 116 case 'g': 117 gflag = true; 118 break; 119 case 'n': 120 nflag = true; 121 break; 122 case 'p': 123 pflag = true; 124 break; 125 case 'r': 126 rflag = true; 127 break; 128 case 's': 129 sflag = true; 130 break; 131 case 'u': 132 uflag = true; 133 break; 134 default: 135 usage(); 136 } 137 } 138 argc -= optind; 139 argv += optind; 140 141 if (iswhoami && argc > 0) 142 usage(); 143 if ((cflag || Aflag || Mflag) && argc > 0) 144 usage(); 145 146 combo = Aflag + Gflag + Mflag + Pflag + gflag + pflag + uflag; 147 if (combo + dflag + sflag > 1) 148 usage(); 149 if (combo > 1) 150 usage(); 151 if (combo == 0 && (nflag || rflag)) 152 usage(); 153 154 pw = *argv ? who(*argv) : NULL; 155 156 if (Mflag && pw != NULL) 157 usage(); 158 159 #ifdef USE_BSM_AUDIT 160 if (Aflag) { 161 auditid(); 162 exit(0); 163 } 164 #endif 165 166 if (cflag) { 167 error = getloginclass(loginclass, sizeof(loginclass)); 168 if (error != 0) 169 err(1, "loginclass"); 170 (void)printf("%s\n", loginclass); 171 exit(0); 172 } 173 174 if (gflag) { 175 id = pw ? pw->pw_gid : rflag ? getgid() : getegid(); 176 if (nflag && (gr = getgrgid(id))) 177 (void)printf("%s\n", gr->gr_name); 178 else 179 (void)printf("%u\n", id); 180 exit(0); 181 } 182 183 if (uflag) { 184 id = pw ? pw->pw_uid : rflag ? getuid() : geteuid(); 185 if (nflag && (pw = getpwuid(id))) 186 (void)printf("%s\n", pw->pw_name); 187 else 188 (void)printf("%u\n", id); 189 exit(0); 190 } 191 192 if (dflag) { 193 dir(pw); 194 exit(0); 195 } 196 197 if (Gflag) { 198 group(pw, nflag); 199 exit(0); 200 } 201 202 if (Mflag) { 203 maclabel(); 204 exit(0); 205 } 206 207 if (Pflag) { 208 pline(pw); 209 exit(0); 210 } 211 212 if (pflag) { 213 pretty(pw); 214 exit(0); 215 } 216 217 if (sflag) { 218 shell(pw); 219 exit(0); 220 } 221 222 id_print(pw); 223 exit(0); 224 } 225 226 static void 227 pretty(struct passwd *pw) 228 { 229 struct group *gr; 230 u_int eid, rid; 231 char *login; 232 233 if (pw) { 234 (void)printf("uid\t%s\n", pw->pw_name); 235 (void)printf("groups\t"); 236 group(pw, true); 237 } else { 238 if ((login = getlogin()) == NULL) 239 err(1, "getlogin"); 240 241 pw = getpwuid(rid = getuid()); 242 if (pw == NULL || strcmp(login, pw->pw_name)) 243 (void)printf("login\t%s\n", login); 244 if (pw) 245 (void)printf("uid\t%s\n", pw->pw_name); 246 else 247 (void)printf("uid\t%u\n", rid); 248 249 if ((eid = geteuid()) != rid) { 250 if ((pw = getpwuid(eid))) 251 (void)printf("euid\t%s\n", pw->pw_name); 252 else 253 (void)printf("euid\t%u\n", eid); 254 } 255 if ((rid = getgid()) != (eid = getegid())) { 256 if ((gr = getgrgid(rid))) 257 (void)printf("rgid\t%s\n", gr->gr_name); 258 else 259 (void)printf("rgid\t%u\n", rid); 260 } 261 (void)printf("groups\t"); 262 group(NULL, true); 263 } 264 } 265 266 static void 267 id_print(struct passwd *pw) 268 { 269 struct group *gr; 270 gid_t gid, egid, lastgid; 271 uid_t uid, euid; 272 int cnt, ngroups; 273 long ngroups_max; 274 gid_t *groups; 275 const char *fmt; 276 bool print_dbinfo; 277 278 print_dbinfo = pw != NULL; 279 if (print_dbinfo) { 280 uid = pw->pw_uid; 281 gid = pw->pw_gid; 282 } 283 else { 284 uid = getuid(); 285 gid = getgid(); 286 pw = getpwuid(uid); 287 } 288 289 ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; 290 if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) 291 err(1, "malloc"); 292 293 if (print_dbinfo) { 294 ngroups = ngroups_max; 295 getgrouplist(pw->pw_name, gid, groups, &ngroups); 296 } 297 else { 298 ngroups = getgroups(ngroups_max, groups); 299 } 300 301 /* 302 * We always resolve uids and gids where we can to a name, even if we 303 * are printing the running process credentials, to be nice. 304 */ 305 if (pw != NULL) 306 printf("uid=%u(%s)", uid, pw->pw_name); 307 else 308 printf("uid=%u", uid); 309 printf(" gid=%u", gid); 310 if ((gr = getgrgid(gid))) 311 (void)printf("(%s)", gr->gr_name); 312 if (!print_dbinfo && (euid = geteuid()) != uid) { 313 (void)printf(" euid=%u", euid); 314 if ((pw = getpwuid(euid))) 315 (void)printf("(%s)", pw->pw_name); 316 } 317 if (!print_dbinfo && (egid = getegid()) != gid) { 318 (void)printf(" egid=%u", egid); 319 if ((gr = getgrgid(egid))) 320 (void)printf("(%s)", gr->gr_name); 321 } 322 fmt = " groups=%u"; 323 for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) { 324 if (lastgid == (gid = groups[cnt])) 325 continue; 326 printf(fmt, gid); 327 fmt = ",%u"; 328 if ((gr = getgrgid(gid))) 329 printf("(%s)", gr->gr_name); 330 lastgid = gid; 331 } 332 printf("\n"); 333 free(groups); 334 } 335 336 #ifdef USE_BSM_AUDIT 337 static void 338 auditid(void) 339 { 340 auditinfo_t auditinfo; 341 auditinfo_addr_t ainfo_addr; 342 int ret, extended; 343 344 extended = 0; 345 ret = getaudit(&auditinfo); 346 if (ret < 0 && errno == E2BIG) { 347 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) 348 err(1, "getaudit_addr"); 349 extended = 1; 350 } else if (ret < 0) 351 err(1, "getaudit"); 352 if (extended != 0) { 353 (void) printf("auid=%d\n" 354 "mask.success=0x%08x\n" 355 "mask.failure=0x%08x\n" 356 "asid=%d\n" 357 "termid_addr.port=0x%08jx\n" 358 "termid_addr.addr[0]=0x%08x\n" 359 "termid_addr.addr[1]=0x%08x\n" 360 "termid_addr.addr[2]=0x%08x\n" 361 "termid_addr.addr[3]=0x%08x\n", 362 ainfo_addr.ai_auid, ainfo_addr.ai_mask.am_success, 363 ainfo_addr.ai_mask.am_failure, ainfo_addr.ai_asid, 364 (uintmax_t)ainfo_addr.ai_termid.at_port, 365 ainfo_addr.ai_termid.at_addr[0], 366 ainfo_addr.ai_termid.at_addr[1], 367 ainfo_addr.ai_termid.at_addr[2], 368 ainfo_addr.ai_termid.at_addr[3]); 369 } else { 370 (void) printf("auid=%d\n" 371 "mask.success=0x%08x\n" 372 "mask.failure=0x%08x\n" 373 "asid=%d\n" 374 "termid.port=0x%08jx\n" 375 "termid.machine=0x%08x\n", 376 auditinfo.ai_auid, auditinfo.ai_mask.am_success, 377 auditinfo.ai_mask.am_failure, 378 auditinfo.ai_asid, (uintmax_t)auditinfo.ai_termid.port, 379 auditinfo.ai_termid.machine); 380 } 381 } 382 #endif 383 384 static void 385 group(struct passwd *pw, bool nflag) 386 { 387 struct group *gr; 388 int cnt, id, lastid, ngroups; 389 long ngroups_max; 390 gid_t *groups; 391 const char *fmt; 392 393 ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; 394 if ((groups = malloc(sizeof(gid_t) * (ngroups_max))) == NULL) 395 err(1, "malloc"); 396 397 if (pw) { 398 ngroups = ngroups_max; 399 (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); 400 } else { 401 ngroups = getgroups(ngroups_max, groups); 402 } 403 fmt = nflag ? "%s" : "%u"; 404 for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) { 405 if (lastid == (id = groups[cnt])) 406 continue; 407 if (nflag) { 408 if ((gr = getgrgid(id))) 409 (void)printf(fmt, gr->gr_name); 410 else 411 (void)printf(*fmt == ' ' ? " %u" : "%u", 412 id); 413 fmt = " %s"; 414 } else { 415 (void)printf(fmt, id); 416 fmt = " %u"; 417 } 418 lastid = id; 419 } 420 (void)printf("\n"); 421 free(groups); 422 } 423 424 static void 425 maclabel(void) 426 { 427 char *string; 428 mac_t label; 429 int error; 430 431 error = mac_prepare_process_label(&label); 432 if (error == -1) 433 errx(1, "mac_prepare_type: %s", strerror(errno)); 434 435 error = mac_get_proc(label); 436 if (error == -1) 437 errx(1, "mac_get_proc: %s", strerror(errno)); 438 439 error = mac_to_text(label, &string); 440 if (error == -1) 441 errx(1, "mac_to_text: %s", strerror(errno)); 442 443 (void)printf("%s\n", string); 444 mac_free(label); 445 free(string); 446 } 447 448 static struct passwd * 449 who(char *u) 450 { 451 struct passwd *pw; 452 long id; 453 char *ep; 454 455 /* 456 * Translate user argument into a pw pointer. First, try to 457 * get it as specified. If that fails, try it as a number. 458 */ 459 if ((pw = getpwnam(u))) 460 return(pw); 461 id = strtol(u, &ep, 10); 462 if (*u && !*ep && (pw = getpwuid(id))) 463 return(pw); 464 errx(1, "%s: no such user", u); 465 /* NOTREACHED */ 466 } 467 468 static void 469 pline(struct passwd *pw) 470 { 471 if (pw == NULL) { 472 if ((pw = getpwuid(getuid())) == NULL) 473 err(1, "getpwuid"); 474 } 475 (void)printf("%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", pw->pw_name, 476 pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, 477 (long)pw->pw_change, (long)pw->pw_expire, pw->pw_gecos, 478 pw->pw_dir, pw->pw_shell); 479 } 480 481 static void 482 dir(struct passwd *pw) 483 { 484 if (pw == NULL) { 485 if ((pw = getpwuid(getuid())) == NULL) 486 err(1, "getpwuid"); 487 } 488 printf("%s\n", pw->pw_dir); 489 } 490 491 static void 492 shell(struct passwd *pw) 493 { 494 if (pw == NULL) { 495 if ((pw = getpwuid(getuid())) == NULL) 496 err(1, "getpwuid"); 497 } 498 printf("%s\n", pw->pw_shell); 499 } 500 501 static void 502 usage(void) 503 { 504 if (isgroups) 505 (void)fprintf(stderr, "usage: groups [user]\n"); 506 else if (iswhoami) 507 (void)fprintf(stderr, "usage: whoami\n"); 508 else 509 (void)fprintf(stderr, 510 "usage: id [user]\n" 511 #ifdef USE_BSM_AUDIT 512 " id -A\n" 513 #endif 514 " id -G [-n] [user]\n" 515 " id -M\n" 516 " id -P [user]\n" 517 " id -c\n" 518 " id -d [user]\n" 519 " id -g [-nr] [user]\n" 520 " id -p [user]\n" 521 " id -s [user]\n" 522 " id -u [-nr] [user]\n"); 523 exit(1); 524 } 525