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