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