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