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 #ifdef USE_BSM_AUDIT 71 bool Aflag; 72 #endif 73 bool Gflag, Mflag, Pflag; 74 bool cflag, dflag, gflag, nflag, pflag, rflag, sflag, uflag; 75 int ch, combo, error, id; 76 const char *myname, *optstr; 77 char loginclass[MAXLOGNAME]; 78 79 #ifdef USE_BSM_AUDIT 80 Aflag = false; 81 #endif 82 Gflag = Mflag = Pflag = false; 83 cflag = dflag = gflag = nflag = pflag = rflag = sflag = uflag = false; 84 85 myname = getprogname(); 86 optstr = "AGMPacdgnprsu"; 87 if (strcmp(myname, "groups") == 0) { 88 isgroups = true; 89 optstr = ""; 90 Gflag = nflag = true; 91 } 92 else if (strcmp(myname, "whoami") == 0) { 93 iswhoami = true; 94 optstr = ""; 95 uflag = nflag = true; 96 } 97 98 while ((ch = getopt(argc, argv, optstr)) != -1) { 99 switch(ch) { 100 #ifdef USE_BSM_AUDIT 101 case 'A': 102 Aflag = true; 103 break; 104 #endif 105 case 'G': 106 Gflag = true; 107 break; 108 case 'M': 109 Mflag = true; 110 break; 111 case 'P': 112 Pflag = true; 113 break; 114 case 'a': 115 break; 116 case 'c': 117 cflag = true; 118 break; 119 case 'd': 120 dflag = true; 121 break; 122 case 'g': 123 gflag = true; 124 break; 125 case 'n': 126 nflag = true; 127 break; 128 case 'p': 129 pflag = true; 130 break; 131 case 'r': 132 rflag = true; 133 break; 134 case 's': 135 sflag = true; 136 break; 137 case 'u': 138 uflag = true; 139 break; 140 default: 141 usage(); 142 } 143 } 144 argc -= optind; 145 argv += optind; 146 147 if (iswhoami && argc > 0) 148 usage(); 149 if ((cflag || Aflag || Mflag) && argc > 0) 150 usage(); 151 152 combo = Aflag + Gflag + Mflag + Pflag + gflag + pflag + uflag; 153 if (combo + dflag + sflag > 1) 154 usage(); 155 if (combo > 1) 156 usage(); 157 if (combo == 0 && (nflag || rflag)) 158 usage(); 159 160 pw = *argv ? who(*argv) : NULL; 161 162 if (Mflag && pw != NULL) 163 usage(); 164 165 #ifdef USE_BSM_AUDIT 166 if (Aflag) { 167 auditid(); 168 exit(0); 169 } 170 #endif 171 172 if (cflag) { 173 error = getloginclass(loginclass, sizeof(loginclass)); 174 if (error != 0) 175 err(1, "loginclass"); 176 (void)printf("%s\n", loginclass); 177 exit(0); 178 } 179 180 if (gflag) { 181 id = pw ? pw->pw_gid : rflag ? getgid() : getegid(); 182 if (nflag && (gr = getgrgid(id))) 183 (void)printf("%s\n", gr->gr_name); 184 else 185 (void)printf("%u\n", id); 186 exit(0); 187 } 188 189 if (uflag) { 190 id = pw ? pw->pw_uid : rflag ? getuid() : geteuid(); 191 if (nflag && (pw = getpwuid(id))) 192 (void)printf("%s\n", pw->pw_name); 193 else 194 (void)printf("%u\n", id); 195 exit(0); 196 } 197 198 if (dflag) { 199 dir(pw); 200 exit(0); 201 } 202 203 if (Gflag) { 204 group(pw, nflag); 205 exit(0); 206 } 207 208 if (Mflag) { 209 maclabel(); 210 exit(0); 211 } 212 213 if (Pflag) { 214 pline(pw); 215 exit(0); 216 } 217 218 if (pflag) { 219 pretty(pw); 220 exit(0); 221 } 222 223 if (sflag) { 224 shell(pw); 225 exit(0); 226 } 227 228 id_print(pw); 229 exit(0); 230 } 231 232 static void 233 pretty(struct passwd *pw) 234 { 235 struct group *gr; 236 u_int eid, rid; 237 char *login; 238 239 if (pw) { 240 (void)printf("uid\t%s\n", pw->pw_name); 241 (void)printf("groups\t"); 242 group(pw, true); 243 } else { 244 if ((login = getlogin()) == NULL) 245 err(1, "getlogin"); 246 247 pw = getpwuid(rid = getuid()); 248 if (pw == NULL || strcmp(login, pw->pw_name)) 249 (void)printf("login\t%s\n", login); 250 if (pw) 251 (void)printf("uid\t%s\n", pw->pw_name); 252 else 253 (void)printf("uid\t%u\n", rid); 254 255 if ((eid = geteuid()) != rid) { 256 if ((pw = getpwuid(eid))) 257 (void)printf("euid\t%s\n", pw->pw_name); 258 else 259 (void)printf("euid\t%u\n", eid); 260 } 261 if ((rid = getgid()) != (eid = getegid())) { 262 if ((gr = getgrgid(rid))) 263 (void)printf("rgid\t%s\n", gr->gr_name); 264 else 265 (void)printf("rgid\t%u\n", rid); 266 } 267 (void)printf("groups\t"); 268 group(NULL, true); 269 } 270 } 271 272 static void 273 id_print(struct passwd *pw) 274 { 275 struct group *gr; 276 gid_t gid, egid, lastgid; 277 uid_t uid, euid; 278 int cnt, ngroups; 279 long ngroups_max; 280 gid_t *groups; 281 const char *fmt; 282 bool print_dbinfo; 283 284 print_dbinfo = pw != NULL; 285 if (print_dbinfo) { 286 uid = pw->pw_uid; 287 gid = pw->pw_gid; 288 } 289 else { 290 uid = getuid(); 291 gid = getgid(); 292 pw = getpwuid(uid); 293 } 294 295 ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; 296 if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) 297 err(1, "malloc"); 298 299 if (print_dbinfo) { 300 ngroups = ngroups_max; 301 getgrouplist(pw->pw_name, gid, groups, &ngroups); 302 } 303 else { 304 ngroups = getgroups(ngroups_max, groups); 305 } 306 307 /* 308 * We always resolve uids and gids where we can to a name, even if we 309 * are printing the running process credentials, to be nice. 310 */ 311 if (pw != NULL) 312 printf("uid=%u(%s)", uid, pw->pw_name); 313 else 314 printf("uid=%u", uid); 315 printf(" gid=%u", gid); 316 if ((gr = getgrgid(gid))) 317 (void)printf("(%s)", gr->gr_name); 318 if (!print_dbinfo && (euid = geteuid()) != uid) { 319 (void)printf(" euid=%u", euid); 320 if ((pw = getpwuid(euid))) 321 (void)printf("(%s)", pw->pw_name); 322 } 323 if (!print_dbinfo && (egid = getegid()) != gid) { 324 (void)printf(" egid=%u", egid); 325 if ((gr = getgrgid(egid))) 326 (void)printf("(%s)", gr->gr_name); 327 } 328 fmt = " groups=%u"; 329 for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) { 330 if (lastgid == (gid = groups[cnt])) 331 continue; 332 printf(fmt, gid); 333 fmt = ",%u"; 334 if ((gr = getgrgid(gid))) 335 printf("(%s)", gr->gr_name); 336 lastgid = gid; 337 } 338 printf("\n"); 339 free(groups); 340 } 341 342 #ifdef USE_BSM_AUDIT 343 static void 344 auditid(void) 345 { 346 auditinfo_t auditinfo; 347 auditinfo_addr_t ainfo_addr; 348 int ret, extended; 349 350 extended = 0; 351 ret = getaudit(&auditinfo); 352 if (ret < 0 && errno == E2BIG) { 353 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) 354 err(1, "getaudit_addr"); 355 extended = 1; 356 } else if (ret < 0) 357 err(1, "getaudit"); 358 if (extended != 0) { 359 (void) printf("auid=%d\n" 360 "mask.success=0x%08x\n" 361 "mask.failure=0x%08x\n" 362 "asid=%d\n" 363 "termid_addr.port=0x%08jx\n" 364 "termid_addr.addr[0]=0x%08x\n" 365 "termid_addr.addr[1]=0x%08x\n" 366 "termid_addr.addr[2]=0x%08x\n" 367 "termid_addr.addr[3]=0x%08x\n", 368 ainfo_addr.ai_auid, ainfo_addr.ai_mask.am_success, 369 ainfo_addr.ai_mask.am_failure, ainfo_addr.ai_asid, 370 (uintmax_t)ainfo_addr.ai_termid.at_port, 371 ainfo_addr.ai_termid.at_addr[0], 372 ainfo_addr.ai_termid.at_addr[1], 373 ainfo_addr.ai_termid.at_addr[2], 374 ainfo_addr.ai_termid.at_addr[3]); 375 } else { 376 (void) printf("auid=%d\n" 377 "mask.success=0x%08x\n" 378 "mask.failure=0x%08x\n" 379 "asid=%d\n" 380 "termid.port=0x%08jx\n" 381 "termid.machine=0x%08x\n", 382 auditinfo.ai_auid, auditinfo.ai_mask.am_success, 383 auditinfo.ai_mask.am_failure, 384 auditinfo.ai_asid, (uintmax_t)auditinfo.ai_termid.port, 385 auditinfo.ai_termid.machine); 386 } 387 } 388 #endif 389 390 static void 391 group(struct passwd *pw, bool nflag) 392 { 393 struct group *gr; 394 int cnt, id, lastid, ngroups; 395 long ngroups_max; 396 gid_t *groups; 397 const char *fmt; 398 399 ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; 400 if ((groups = malloc(sizeof(gid_t) * (ngroups_max))) == NULL) 401 err(1, "malloc"); 402 403 if (pw) { 404 ngroups = ngroups_max; 405 (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); 406 } else { 407 ngroups = getgroups(ngroups_max, groups); 408 } 409 fmt = nflag ? "%s" : "%u"; 410 for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) { 411 if (lastid == (id = groups[cnt])) 412 continue; 413 if (nflag) { 414 if ((gr = getgrgid(id))) 415 (void)printf(fmt, gr->gr_name); 416 else 417 (void)printf(*fmt == ' ' ? " %u" : "%u", 418 id); 419 fmt = " %s"; 420 } else { 421 (void)printf(fmt, id); 422 fmt = " %u"; 423 } 424 lastid = id; 425 } 426 (void)printf("\n"); 427 free(groups); 428 } 429 430 static void 431 maclabel(void) 432 { 433 char *string; 434 mac_t label; 435 int error; 436 437 error = mac_prepare_process_label(&label); 438 if (error == -1) 439 errx(1, "mac_prepare_type: %s", strerror(errno)); 440 441 error = mac_get_proc(label); 442 if (error == -1) 443 errx(1, "mac_get_proc: %s", strerror(errno)); 444 445 error = mac_to_text(label, &string); 446 if (error == -1) 447 errx(1, "mac_to_text: %s", strerror(errno)); 448 449 (void)printf("%s\n", string); 450 mac_free(label); 451 free(string); 452 } 453 454 static struct passwd * 455 who(char *u) 456 { 457 struct passwd *pw; 458 long id; 459 char *ep; 460 461 /* 462 * Translate user argument into a pw pointer. First, try to 463 * get it as specified. If that fails, try it as a number. 464 */ 465 if ((pw = getpwnam(u))) 466 return(pw); 467 id = strtol(u, &ep, 10); 468 if (*u && !*ep && (pw = getpwuid(id))) 469 return(pw); 470 errx(1, "%s: no such user", u); 471 /* NOTREACHED */ 472 } 473 474 static void 475 pline(struct passwd *pw) 476 { 477 if (pw == NULL) { 478 if ((pw = getpwuid(getuid())) == NULL) 479 err(1, "getpwuid"); 480 } 481 (void)printf("%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", pw->pw_name, 482 pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class, 483 (long)pw->pw_change, (long)pw->pw_expire, pw->pw_gecos, 484 pw->pw_dir, pw->pw_shell); 485 } 486 487 static void 488 dir(struct passwd *pw) 489 { 490 if (pw == NULL) { 491 if ((pw = getpwuid(getuid())) == NULL) 492 err(1, "getpwuid"); 493 } 494 printf("%s\n", pw->pw_dir); 495 } 496 497 static void 498 shell(struct passwd *pw) 499 { 500 if (pw == NULL) { 501 if ((pw = getpwuid(getuid())) == NULL) 502 err(1, "getpwuid"); 503 } 504 printf("%s\n", pw->pw_shell); 505 } 506 507 static void 508 usage(void) 509 { 510 if (isgroups) 511 (void)fprintf(stderr, "usage: groups [user]\n"); 512 else if (iswhoami) 513 (void)fprintf(stderr, "usage: whoami\n"); 514 else 515 (void)fprintf(stderr, 516 "usage: id [user]\n" 517 #ifdef USE_BSM_AUDIT 518 " id -A\n" 519 #endif 520 " id -G [-n] [user]\n" 521 " id -M\n" 522 " id -P [user]\n" 523 " id -c\n" 524 " id -d [user]\n" 525 " id -g [-nr] [user]\n" 526 " id -p [user]\n" 527 " id -s [user]\n" 528 " id -u [-nr] [user]\n"); 529 exit(1); 530 } 531