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