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