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