1/*- 2 * Copyright (c) 1996 by 3 * Sean Eric Fagan <sef@kithrup.com> 4 * David Nugent <davidn@blaze.net.au> 5 * All rights reserved. 6 * 7 * Portions copyright (c) 1995,1997 8 * Berkeley Software Design, Inc. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, is permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice immediately at the beginning of the file, without modification, 16 * this list of conditions, and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. This work was done expressly for inclusion into FreeBSD. Other use 21 * is permitted provided this notation is included. 22 * 4. Absolutely no warranty of function or purpose is made by the authors. 23 * 5. Modifications may be freely made to this file providing the above 24 * conditions are met. 25 * 26 * Low-level routines relating to the user capabilities database 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/lib/libutil/login_cap.c 318121 2017-05-09 23:31:09Z pfg $"); 31 32#include <sys/types.h> 33#include <sys/time.h> 34#include <sys/resource.h> 35#include <sys/param.h> 36#include <errno.h> 37#include <fcntl.h> 38#include <libutil.h> 39#include <login_cap.h> 40#include <pwd.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <syslog.h> 45#include <unistd.h> 46 47/* 48 * allocstr() 49 * Manage a single static pointer for handling a local char* buffer, 50 * resizing as necessary to contain the string. 51 * 52 * allocarray() 53 * Manage a static array for handling a group of strings, resizing 54 * when necessary. 55 */ 56 57static int lc_object_count = 0; 58 59static size_t internal_stringsz = 0; 60static char * internal_string = NULL; 61static size_t internal_arraysz = 0; 62static const char ** internal_array = NULL; 63 64static char path_login_conf[] = _PATH_LOGIN_CONF; 65 66static char * 67allocstr(const char *str) 68{ 69 char *p; 70 71 size_t sz = strlen(str) + 1; /* realloc() only if necessary */ 72 if (sz <= internal_stringsz) 73 p = strcpy(internal_string, str); 74 else if ((p = realloc(internal_string, sz)) != NULL) { 75 internal_stringsz = sz; 76 internal_string = strcpy(p, str); 77 } 78 return p; 79} 80 81 82static const char ** 83allocarray(size_t sz) 84{ 85 static const char **p; 86 87 if (sz <= internal_arraysz) 88 p = internal_array; 89 else if ((p = reallocarray(internal_array, sz, sizeof(char*))) != NULL) { 90 internal_arraysz = sz; 91 internal_array = p; 92 } 93 return p; 94} 95 96 97/* 98 * arrayize() 99 * Turn a simple string <str> separated by any of 100 * the set of <chars> into an array. The last element 101 * of the array will be NULL, as is proper. 102 * Free using freearraystr() 103 */ 104 105static const char ** 106arrayize(const char *str, const char *chars, int *size) 107{ 108 int i; 109 char *ptr; 110 const char *cptr; 111 const char **res = NULL; 112 113 /* count the sub-strings */ 114 for (i = 0, cptr = str; *cptr; i++) { 115 int count = strcspn(cptr, chars); 116 cptr += count; 117 if (*cptr) 118 ++cptr; 119 } 120 121 /* alloc the array */ 122 if ((ptr = allocstr(str)) != NULL) { 123 if ((res = allocarray(++i)) == NULL) 124 free((void *)(uintptr_t)(const void *)str); 125 else { 126 /* now split the string */ 127 i = 0; 128 while (*ptr) { 129 int count = strcspn(ptr, chars); 130 res[i++] = ptr; 131 ptr += count; 132 if (*ptr) 133 *ptr++ = '\0'; 134 } 135 res[i] = NULL; 136 } 137 } 138 139 if (size) 140 *size = i; 141 142 return res; 143} 144 145 146/* 147 * login_close() 148 * Frees up all resources relating to a login class 149 * 150 */ 151 152void 153login_close(login_cap_t * lc) 154{ 155 if (lc) { 156 free(lc->lc_style); 157 free(lc->lc_class); 158 free(lc->lc_cap); 159 free(lc); 160 if (--lc_object_count == 0) { 161 free(internal_string); 162 free(internal_array); 163 internal_array = NULL; 164 internal_arraysz = 0; 165 internal_string = NULL; 166 internal_stringsz = 0; 167 cgetclose(); 168 } 169 } 170} 171 172 173/* 174 * login_getclassbyname() 175 * Get the login class by its name. 176 * If the name given is NULL or empty, the default class 177 * LOGIN_DEFCLASS (i.e., "default") is fetched. 178 * If the name given is LOGIN_MECLASS and 179 * 'pwd' argument is non-NULL and contains an non-NULL 180 * dir entry, then the file _FILE_LOGIN_CONF is picked 181 * up from that directory and used before the system 182 * login database. In that case the system login database 183 * is looked up using LOGIN_MECLASS, too, which is a bug. 184 * Return a filled-out login_cap_t structure, including 185 * class name, and the capability record buffer. 186 */ 187 188login_cap_t * 189login_getclassbyname(char const *name, const struct passwd *pwd) 190{ 191 login_cap_t *lc; 192 193 if ((lc = malloc(sizeof(login_cap_t))) != NULL) { 194 int r, me, i = 0; 195 uid_t euid = 0; 196 gid_t egid = 0; 197 const char *msg = NULL; 198 const char *dir; 199 char userpath[MAXPATHLEN]; 200 201 static char *login_dbarray[] = { NULL, NULL, NULL }; 202 203 me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); 204 dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; 205 /* 206 * Switch to user mode before checking/reading its ~/.login_conf 207 * - some NFSes have root read access disabled. 208 * 209 * XXX: This fails to configure additional groups. 210 */ 211 if (dir) { 212 euid = geteuid(); 213 egid = getegid(); 214 (void)setegid(pwd->pw_gid); 215 (void)seteuid(pwd->pw_uid); 216 } 217 218 if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, 219 _FILE_LOGIN_CONF) < MAXPATHLEN) { 220 if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) 221 login_dbarray[i++] = userpath; 222 } 223 /* 224 * XXX: Why to add the system database if the class is `me'? 225 */ 226 if (_secure_path(path_login_conf, 0, 0) != -1) 227 login_dbarray[i++] = path_login_conf; 228 login_dbarray[i] = NULL; 229 230 memset(lc, 0, sizeof(login_cap_t)); 231 lc->lc_cap = lc->lc_class = lc->lc_style = NULL; 232 233 if (name == NULL || *name == '\0') 234 name = LOGIN_DEFCLASS; 235 236 switch (cgetent(&lc->lc_cap, login_dbarray, name)) { 237 case -1: /* Failed, entry does not exist */ 238 if (me) 239 break; /* Don't retry default on 'me' */ 240 if (i == 0) 241 r = -1; 242 else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) 243 close(r); 244 /* 245 * If there's at least one login class database, 246 * and we aren't searching for a default class 247 * then complain about a non-existent class. 248 */ 249 if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0) 250 syslog(LOG_ERR, "login_getclass: unknown class '%s'", name); 251 /* fall-back to default class */ 252 name = LOGIN_DEFCLASS; 253 msg = "%s: no default/fallback class '%s'"; 254 if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) 255 break; 256 /* FALLTHROUGH - just return system defaults */ 257 case 0: /* success! */ 258 if ((lc->lc_class = strdup(name)) != NULL) { 259 if (dir) { 260 (void)seteuid(euid); 261 (void)setegid(egid); 262 } 263 ++lc_object_count; 264 return lc; 265 } 266 msg = "%s: strdup: %m"; 267 break; 268 case -2: 269 msg = "%s: retrieving class information: %m"; 270 break; 271 case -3: 272 msg = "%s: 'tc=' reference loop '%s'"; 273 break; 274 case 1: 275 msg = "couldn't resolve 'tc=' reference in '%s'"; 276 break; 277 default: 278 msg = "%s: unexpected cgetent() error '%s': %m"; 279 break; 280 } 281 if (dir) { 282 (void)seteuid(euid); 283 (void)setegid(egid); 284 } 285 if (msg != NULL) 286 syslog(LOG_ERR, msg, "login_getclass", name); 287 free(lc); 288 } 289 290 return NULL; 291} 292 293 294 295/* 296 * login_getclass() 297 * Get the login class for the system (only) login class database. 298 * Return a filled-out login_cap_t structure, including 299 * class name, and the capability record buffer. 300 */ 301 302login_cap_t * 303login_getclass(const char *cls) 304{ 305 return login_getclassbyname(cls, NULL); 306} 307 308 309/* 310 * login_getpwclass() 311 * Get the login class for a given password entry from 312 * the system (only) login class database. 313 * If the password entry's class field is not set, or 314 * the class specified does not exist, then use the 315 * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged 316 * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. 317 * Return a filled-out login_cap_t structure, including 318 * class name, and the capability record buffer. 319 */ 320 321login_cap_t * 322login_getpwclass(const struct passwd *pwd) 323{ 324 const char *cls = NULL; 325 326 if (pwd != NULL) { 327 cls = pwd->pw_class; 328 if (cls == NULL || *cls == '\0') 329 cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; 330 } 331 /* 332 * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', 333 * so NULL can be passed instead of pwd for more safety. 334 */ 335 return login_getclassbyname(cls, pwd); 336} 337 338 339/* 340 * login_getuserclass() 341 * Get the `me' login class, allowing user overrides via ~/.login_conf. 342 * Note that user overrides are allowed only in the `me' class. 343 */ 344 345login_cap_t * 346login_getuserclass(const struct passwd *pwd) 347{ 348 return login_getclassbyname(LOGIN_MECLASS, pwd); 349} 350 351 352/* 353 * login_getcapstr() 354 * Given a login_cap entry, and a capability name, return the 355 * value defined for that capability, a default if not found, or 356 * an error string on error. 357 */ 358 359const char * 360login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) 361{ 362 char *res; 363 int ret; 364 365 if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') 366 return def; 367 368 if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) 369 return def; 370 return (ret >= 0) ? res : error; 371} 372 373 374/* 375 * login_getcaplist() 376 * Given a login_cap entry, and a capability name, return the 377 * value defined for that capability split into an array of 378 * strings. 379 */ 380 381const char ** 382login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) 383{ 384 const char *lstring; 385 386 if (chars == NULL) 387 chars = ", \t"; 388 if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) 389 return arrayize(lstring, chars, NULL); 390 return NULL; 391} 392 393 394/* 395 * login_getpath() 396 * From the login_cap_t <lc>, get the capability <cap> which is 397 * formatted as either a space or comma delimited list of paths 398 * and append them all into a string and separate by semicolons. 399 * If there is an error of any kind, return <error>. 400 */ 401 402const char * 403login_getpath(login_cap_t *lc, const char *cap, const char *error) 404{ 405 const char *str; 406 char *ptr; 407 int count; 408 409 str = login_getcapstr(lc, cap, NULL, NULL); 410 if (str == NULL) 411 return error; 412 ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ 413 while (*ptr) { 414 count = strcspn(ptr, ", \t"); 415 ptr += count; 416 if (*ptr) 417 *ptr++ = ':'; 418 } 419 return str; 420} 421 422 423static int 424isinfinite(const char *s) 425{ 426 static const char *infs[] = { 427 "infinity", 428 "inf", 429 "unlimited", 430 "unlimit", 431 "-1", 432 NULL 433 }; 434 const char **i = &infs[0]; 435 436 while (*i != NULL) { 437 if (strcasecmp(s, *i) == 0) 438 return 1; 439 ++i; 440 } 441 return 0; 442} 443 444 445static u_quad_t 446rmultiply(u_quad_t n1, u_quad_t n2) 447{ 448 u_quad_t m, r; 449 int b1, b2; 450 451 static int bpw = 0; 452 453 /* Handle simple cases */ 454 if (n1 == 0 || n2 == 0) 455 return 0; 456 if (n1 == 1) 457 return n2; 458 if (n2 == 1) 459 return n1; 460 461 /* 462 * sizeof() returns number of bytes needed for storage. 463 * This may be different from the actual number of useful bits. 464 */ 465 if (!bpw) { 466 bpw = sizeof(u_quad_t) * 8; 467 while (((u_quad_t)1 << (bpw-1)) == 0) 468 --bpw; 469 } 470 471 /* 472 * First check the magnitude of each number. If the sum of the 473 * magnatude is way to high, reject the number. (If this test 474 * is not done then the first multiply below may overflow.) 475 */ 476 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 477 ; 478 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 479 ; 480 if (b1 + b2 - 2 > bpw) { 481 errno = ERANGE; 482 return (UQUAD_MAX); 483 } 484 485 /* 486 * Decompose the multiplication to be: 487 * h1 = n1 & ~1 488 * h2 = n2 & ~1 489 * l1 = n1 & 1 490 * l2 = n2 & 1 491 * (h1 + l1) * (h2 + l2) 492 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 493 * 494 * Since h1 && h2 do not have the low bit set, we can then say: 495 * 496 * (h1>>1 * h2>>1 * 4) + ... 497 * 498 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 499 * overflow. 500 * 501 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 502 * then adding in residual amout will cause an overflow. 503 */ 504 505 m = (n1 >> 1) * (n2 >> 1); 506 if (m >= ((u_quad_t)1 << (bpw-2))) { 507 errno = ERANGE; 508 return (UQUAD_MAX); 509 } 510 m *= 4; 511 512 r = (n1 & n2 & 1) 513 + (n2 & 1) * (n1 & ~(u_quad_t)1) 514 + (n1 & 1) * (n2 & ~(u_quad_t)1); 515 516 if ((u_quad_t)(m + r) < m) { 517 errno = ERANGE; 518 return (UQUAD_MAX); 519 } 520 m += r; 521 522 return (m); 523} 524 525 526/* 527 * login_getcaptime() 528 * From the login_cap_t <lc>, get the capability <cap>, which is 529 * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not 530 * present in <lc>, return <def>; if there is an error of some kind, 531 * return <error>. 532 */ 533 534rlim_t 535login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 536{ 537 char *res, *ep, *oval; 538 int r; 539 rlim_t tot; 540 541 errno = 0; 542 if (lc == NULL || lc->lc_cap == NULL) 543 return def; 544 545 /* 546 * Look for <cap> in lc_cap. 547 * If it's not there (-1), return <def>. 548 * If there's an error, return <error>. 549 */ 550 551 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 552 return def; 553 else if (r < 0) { 554 errno = ERANGE; 555 return error; 556 } 557 558 /* "inf" and "infinity" are special cases */ 559 if (isinfinite(res)) 560 return RLIM_INFINITY; 561 562 /* 563 * Now go through the string, turning something like 1h2m3s into 564 * an integral value. Whee. 565 */ 566 567 errno = 0; 568 tot = 0; 569 oval = res; 570 while (*res) { 571 rlim_t tim = strtoq(res, &ep, 0); 572 rlim_t mult = 1; 573 574 if (ep == NULL || ep == res || errno != 0) { 575 invalid: 576 syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s", 577 lc->lc_class, cap, oval); 578 errno = ERANGE; 579 return error; 580 } 581 /* Look for suffixes */ 582 switch (*ep++) { 583 case 0: 584 ep--; 585 break; /* end of string */ 586 case 's': case 'S': /* seconds */ 587 break; 588 case 'm': case 'M': /* minutes */ 589 mult = 60; 590 break; 591 case 'h': case 'H': /* hours */ 592 mult = 60L * 60L; 593 break; 594 case 'd': case 'D': /* days */ 595 mult = 60L * 60L * 24L; 596 break; 597 case 'w': case 'W': /* weeks */ 598 mult = 60L * 60L * 24L * 7L; 599 break; 600 case 'y': case 'Y': /* 365-day years */ 601 mult = 60L * 60L * 24L * 365L; 602 break; 603 default: 604 goto invalid; 605 } 606 res = ep; 607 tot += rmultiply(tim, mult); 608 if (errno) 609 goto invalid; 610 } 611 612 return tot; 613} 614 615 616/* 617 * login_getcapnum() 618 * From the login_cap_t <lc>, extract the numerical value <cap>. 619 * If it is not present, return <def> for a default, and return 620 * <error> if there is an error. 621 * Like login_getcaptime(), only it only converts to a number, not 622 * to a time; "infinity" and "inf" are 'special.' 623 */ 624 625rlim_t 626login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 627{ 628 char *ep, *res; 629 int r; 630 rlim_t val; 631 632 if (lc == NULL || lc->lc_cap == NULL) 633 return def; 634 635 /* 636 * For BSDI compatibility, try for the tag=<val> first 637 */ 638 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) { 639 long lval; 640 /* string capability not present, so try for tag#<val> as numeric */ 641 if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) 642 return def; /* Not there, so return default */ 643 else if (r >= 0) 644 return (rlim_t)lval; 645 } 646 647 if (r < 0) { 648 errno = ERANGE; 649 return error; 650 } 651 652 if (isinfinite(res)) 653 return RLIM_INFINITY; 654 655 errno = 0; 656 val = strtoq(res, &ep, 0); 657 if (ep == NULL || ep == res || errno != 0) { 658 syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s", 659 lc->lc_class, cap, res); 660 errno = ERANGE; 661 return error; 662 } 663 664 return val; 665} 666 667 668 669/* 670 * login_getcapsize() 671 * From the login_cap_t <lc>, extract the capability <cap>, which is 672 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". 673 * If not present, return <def>, or <error> if there is an error of 674 * some sort. 675 */ 676 677rlim_t 678login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 679{ 680 char *ep, *res, *oval; 681 int r; 682 rlim_t tot; 683 684 if (lc == NULL || lc->lc_cap == NULL) 685 return def; 686 687 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 688 return def; 689 else if (r < 0) { 690 errno = ERANGE; 691 return error; 692 } 693 694 if (isinfinite(res)) 695 return RLIM_INFINITY; 696 697 errno = 0; 698 tot = 0; 699 oval = res; 700 while (*res) { 701 rlim_t siz = strtoq(res, &ep, 0); 702 rlim_t mult = 1; 703 704 if (ep == NULL || ep == res || errno != 0) { 705 invalid: 706 syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s", 707 lc->lc_class, cap, oval); 708 errno = ERANGE; 709 return error; 710 } 711 switch (*ep++) { 712 case 0: /* end of string */ 713 ep--; 714 break; 715 case 'b': case 'B': /* 512-byte blocks */ 716 mult = 512; 717 break; 718 case 'k': case 'K': /* 1024-byte Kilobytes */ 719 mult = 1024; 720 break; 721 case 'm': case 'M': /* 1024-k kbytes */ 722 mult = 1024 * 1024; 723 break; 724 case 'g': case 'G': /* 1Gbyte */ 725 mult = 1024 * 1024 * 1024; 726 break; 727 case 't': case 'T': /* 1TBte */ 728 mult = 1024LL * 1024LL * 1024LL * 1024LL; 729 break; 730 default: 731 goto invalid; 732 } 733 res = ep; 734 tot += rmultiply(siz, mult); 735 if (errno) 736 goto invalid; 737 } 738 739 return tot; 740} 741 742 743/* 744 * login_getcapbool() 745 * From the login_cap_t <lc>, check for the existence of the capability 746 * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return 747 * the whether or not <cap> exists there. 748 */ 749 750int 751login_getcapbool(login_cap_t *lc, const char *cap, int def) 752{ 753 if (lc == NULL || lc->lc_cap == NULL) 754 return def; 755 return (cgetcap(lc->lc_cap, cap, ':') != NULL); 756} 757 758 759/* 760 * login_getstyle() 761 * Given a login_cap entry <lc>, and optionally a type of auth <auth>, 762 * and optionally a style <style>, find the style that best suits these 763 * rules: 764 * 1. If <auth> is non-null, look for an "auth-<auth>=" string 765 * in the capability; if not present, default to "auth=". 766 * 2. If there is no auth list found from (1), default to 767 * "passwd" as an authorization list. 768 * 3. If <style> is non-null, look for <style> in the list of 769 * authorization methods found from (2); if <style> is NULL, default 770 * to LOGIN_DEFSTYLE ("passwd"). 771 * 4. If the chosen style is found in the chosen list of authorization 772 * methods, return that; otherwise, return NULL. 773 * E.g.: 774 * login_getstyle(lc, NULL, "ftp"); 775 * login_getstyle(lc, "login", NULL); 776 * login_getstyle(lc, "skey", "network"); 777 */ 778 779const char * 780login_getstyle(login_cap_t *lc, const char *style, const char *auth) 781{ 782 int i; 783 const char **authtypes = NULL; 784 char *auths= NULL; 785 char realauth[64]; 786 787 static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; 788 789 if (auth != NULL && *auth != '\0') { 790 if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) 791 authtypes = login_getcaplist(lc, realauth, NULL); 792 } 793 794 if (authtypes == NULL) 795 authtypes = login_getcaplist(lc, "auth", NULL); 796 797 if (authtypes == NULL) 798 authtypes = defauthtypes; 799 800 /* 801 * We have at least one authtype now; auths is a comma-separated 802 * (or space-separated) list of authentication types. We have to 803 * convert from this to an array of char*'s; authtypes then gets this. 804 */ 805 i = 0; 806 if (style != NULL && *style != '\0') { 807 while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) 808 i++; 809 } 810 811 lc->lc_style = NULL; 812 if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) 813 lc->lc_style = auths; 814 815 if (lc->lc_style != NULL) 816 lc->lc_style = strdup(lc->lc_style); 817 818 return lc->lc_style; 819} 820