156760Srwatson/*- 2108410Srwatson * Copyright (c) 1996 by 356760Srwatson * Sean Eric Fagan <sef@kithrup.com> 456760Srwatson * David Nugent <davidn@blaze.net.au> 5108410Srwatson * All rights reserved. 6108410Srwatson * 756760Srwatson * Portions copyright (c) 1995,1997 856760Srwatson * Berkeley Software Design, Inc. 956760Srwatson * All rights reserved. 1056760Srwatson * 1156760Srwatson * Redistribution and use in source and binary forms, with or without 1256760Srwatson * modification, is permitted provided that the following conditions 1356760Srwatson * are met: 1456760Srwatson * 1. Redistributions of source code must retain the above copyright 1556760Srwatson * notice immediately at the beginning of the file, without modification, 1656760Srwatson * this list of conditions, and the following disclaimer. 1756760Srwatson * 2. Redistributions in binary form must reproduce the above copyright 1856760Srwatson * notice, this list of conditions and the following disclaimer in the 1956760Srwatson * documentation and/or other materials provided with the distribution. 2056760Srwatson * 3. This work was done expressly for inclusion into FreeBSD. Other use 2156760Srwatson * is permitted provided this notation is included. 2256760Srwatson * 4. Absolutely no warranty of function or purpose is made by the authors. 2356760Srwatson * 5. Modifications may be freely made to this file providing the above 2456760Srwatson * conditions are met. 2556760Srwatson * 2656760Srwatson * Low-level routines relating to the user capabilities database 2756760Srwatson */ 2866076Srwatson 2956760Srwatson#include <sys/types.h> 30108410Srwatson#include <sys/time.h> 3156760Srwatson#include <sys/resource.h> 3279531Sru#include <sys/param.h> 3356760Srwatson#include <errno.h> 3456760Srwatson#include <fcntl.h> 3556760Srwatson#include <libutil.h> 36108410Srwatson#include <login_cap.h> 37108410Srwatson#include <pwd.h> 3859514Sphantom#include <stdio.h> 3959514Sphantom#include <stdlib.h> 4075222Sru#include <string.h> 4156760Srwatson#include <syslog.h> 4284306Sru#include <unistd.h> 4384306Sru 4456760Srwatson/* 4556760Srwatson * allocstr() 4656760Srwatson * Manage a single static pointer for handling a local char* buffer, 4756760Srwatson * resizing as necessary to contain the string. 4856760Srwatson * 4956760Srwatson * allocarray() 50108410Srwatson * Manage a static array for handling a group of strings, resizing 51108410Srwatson * when necessary. 5256760Srwatson */ 5356760Srwatson 5456760Srwatsonstatic int lc_object_count = 0; 55131504Sru 56131504Srustatic size_t internal_stringsz = 0; 5756760Srwatsonstatic char * internal_string = NULL; 5856760Srwatsonstatic size_t internal_arraysz = 0; 59131504Srustatic const char ** internal_array = NULL; 60131504Sru 61108410Srwatsonstatic char path_login_conf[] = _PATH_LOGIN_CONF; 62108410Srwatson 6356760Srwatsonstatic char * 64108410Srwatsonallocstr(const char *str) 6556760Srwatson{ 6656760Srwatson char *p; 67108410Srwatson 68108410Srwatson size_t sz = strlen(str) + 1; /* realloc() only if necessary */ 6956760Srwatson if (sz <= internal_stringsz) 70108410Srwatson p = strcpy(internal_string, str); 71108410Srwatson else if ((p = realloc(internal_string, sz)) != NULL) { 72108410Srwatson internal_stringsz = sz; 73108410Srwatson internal_string = strcpy(p, str); 74108410Srwatson } 7570481Sru return p; 7656760Srwatson} 77140288Sru 78140288Sru 79140288Srustatic const char ** 80140288Sruallocarray(size_t sz) 81140288Sru{ 82140288Sru static const char **p; 83140288Sru 84140288Sru if (sz <= internal_arraysz) 85140288Sru p = internal_array; 86140288Sru else if ((p = reallocarray(internal_array, sz, sizeof(char*))) != NULL) { 8756760Srwatson internal_arraysz = sz; 88140288Sru internal_array = p; 89140288Sru } 90140288Sru return p; 91140288Sru} 92140288Sru 93140288Sru 94140288Sru/* 9556760Srwatson * This is a variant of strcspn, which checks for quoted 96140288Sru * strings. That is,: 97140288Sru * strcspn_quote("how 'now, brown' cow", ",", NULL); 9856760Srwatson * will return the index for the nul, rather than the comma, because 99140288Sru * the string is quoted. It does not handle escaped characters 100140288Sru * at this time. 10156760Srwatson */ 102140288Srustatic size_t 10370481Srustrcspn_quote(const char *str, const char *exclude, int *is_quoted) 10456760Srwatson{ 10556760Srwatson size_t indx = 0; 10656760Srwatson char quote = 0; 10779754Sdd 10856760Srwatson if (str == NULL) 10968716Sru return 0; 11068716Sru 11156760Srwatson if (is_quoted) 11256760Srwatson *is_quoted = 0; 11382642Sru 11456760Srwatson for (indx = 0; str[indx] != 0; indx++) { 11556760Srwatson if (quote && str[indx] == quote) { 11656760Srwatson if (is_quoted) 11756760Srwatson *is_quoted = 1; 11856760Srwatson quote = 0; 11956760Srwatson continue; 12056760Srwatson } 12156760Srwatson if (quote == 0 && 12256760Srwatson (str[indx] == '\'' || str[indx] == '"')) { 12356760Srwatson quote = str[indx]; 12456760Srwatson continue; 12556760Srwatson } 12656760Srwatson if (quote == 0 && 12756760Srwatson strchr(exclude, str[indx]) != NULL) 12856760Srwatson return indx; 12956760Srwatson } 13056760Srwatson return indx; 13170481Sru} 13256760Srwatson 13356760Srwatson/* 13470481Sru * Remove quotes from the given string. 13556760Srwatson * It's a very simplistic approach: the first 13670481Sru * single or double quote it finds, it looks for 13756760Srwatson * the next one, and if it finds it, moves the 13856760Srwatson * entire string backwards in two chunks 13956760Srwatson * (first quote + 1 to first quote, length 14056760Srwatson * rest of string, and then second quote + 1 14156760Srwatson * to second quote, length rest of the string). 14256760Srwatson */ 14356760Srwatsonstatic void 14456760Srwatsonremove_quotes(char *str) 14556760Srwatson{ 14656760Srwatson static const char *quote_chars = "'\""; 14756760Srwatson char qc = 0; 14856760Srwatson int found = 0; 14956760Srwatson 15056760Srwatson do { 15156760Srwatson char *loc = NULL; 15256760Srwatson 15356760Srwatson found = 0; 15456760Srwatson /* 15556760Srwatson * If qc is 0, then we haven't found 15656760Srwatson * a quote yet, so do a strcspn search. 157131504Sru */ 158131504Sru if (qc == 0) { 15956760Srwatson size_t indx; 160131504Sru indx = strcspn(str, quote_chars); 161131504Sru if (str[indx] == '\0') 16268716Sru return; /* We're done */ 16368716Sru loc = str + indx; 16456760Srwatson qc = str[indx]; 16556760Srwatson } else { 16656791Smpp /* 16756791Smpp * We've found a quote character, 16856791Smpp * so use strchr to find the next one. 16956760Srwatson */ 17056791Smpp loc = strchr(str, qc); 171 if (loc == NULL) 172 return; 173 qc = 0; 174 } 175 if (loc) { 176 /* 177 * This gives us the location of the 178 * quoted character. We need to move 179 * the entire string down, from loc+1 180 * to loc. 181 */ 182 size_t len = strlen(loc + 1) + 1; 183 memmove(loc, loc + 1, len); 184 found = 1; 185 } 186 } while (found != 0); 187} 188 189/* 190 * arrayize() 191 * Turn a simple string <str> separated by any of 192 * the set of <chars> into an array. The last element 193 * of the array will be NULL, as is proper. 194 * Free using freearraystr() 195 */ 196 197static const char ** 198arrayize(const char *str, const char *chars, int *size) 199{ 200 int i; 201 char *ptr; 202 const char *cptr; 203 const char **res = NULL; 204 205 /* count the sub-strings */ 206 for (i = 0, cptr = str; *cptr; i++) { 207 int count = strcspn_quote(cptr, chars, NULL); 208 cptr += count; 209 if (*cptr) 210 ++cptr; 211 } 212 213 /* alloc the array */ 214 if ((ptr = allocstr(str)) != NULL) { 215 if ((res = allocarray(++i)) == NULL) 216 free((void *)(uintptr_t)(const void *)str); 217 else { 218 /* now split the string */ 219 i = 0; 220 while (*ptr) { 221 int quoted = 0; 222 int count = strcspn_quote(ptr, chars, "ed); 223 char *base = ptr; 224 res[i++] = ptr; 225 ptr += count; 226 if (*ptr) 227 *ptr++ = '\0'; 228 /* 229 * If the string contains a quoted element, we 230 * need to remove the quotes. 231 */ 232 if (quoted) { 233 remove_quotes(base); 234 } 235 236 } 237 res[i] = NULL; 238 } 239 } 240 241 if (size) 242 *size = i; 243 244 return res; 245} 246 247 248/* 249 * login_close() 250 * Frees up all resources relating to a login class 251 * 252 */ 253 254void 255login_close(login_cap_t * lc) 256{ 257 if (lc) { 258 free(lc->lc_style); 259 free(lc->lc_class); 260 free(lc->lc_cap); 261 free(lc); 262 if (--lc_object_count == 0) { 263 free(internal_string); 264 free(internal_array); 265 internal_array = NULL; 266 internal_arraysz = 0; 267 internal_string = NULL; 268 internal_stringsz = 0; 269 cgetclose(); 270 } 271 } 272} 273 274 275/* 276 * login_getclassbyname() 277 * Get the login class by its name. 278 * If the name given is NULL or empty, the default class 279 * LOGIN_DEFCLASS (i.e., "default") is fetched. 280 * If the name given is LOGIN_MECLASS and 281 * 'pwd' argument is non-NULL and contains an non-NULL 282 * dir entry, then the file _FILE_LOGIN_CONF is picked 283 * up from that directory and used before the system 284 * login database. In that case the system login database 285 * is looked up using LOGIN_MECLASS, too, which is a bug. 286 * Return a filled-out login_cap_t structure, including 287 * class name, and the capability record buffer. 288 */ 289 290login_cap_t * 291login_getclassbyname(char const *name, const struct passwd *pwd) 292{ 293 login_cap_t *lc; 294 295 if ((lc = calloc(1, sizeof(login_cap_t))) != NULL) { 296 int r, me, i = 0; 297 uid_t euid = 0; 298 gid_t egid = 0; 299 const char *msg = NULL; 300 const char *dir; 301 char userpath[MAXPATHLEN]; 302 303 static char *login_dbarray[] = { NULL, NULL, NULL }; 304 305 me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0); 306 dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir; 307 /* 308 * Switch to user mode before checking/reading its ~/.login_conf 309 * - some NFSes have root read access disabled. 310 * 311 * XXX: This fails to configure additional groups. 312 */ 313 if (dir) { 314 euid = geteuid(); 315 egid = getegid(); 316 (void)setegid(pwd->pw_gid); 317 (void)seteuid(pwd->pw_uid); 318 } 319 320 if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir, 321 _FILE_LOGIN_CONF) < MAXPATHLEN) { 322 if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1) 323 login_dbarray[i++] = userpath; 324 } 325 /* 326 * XXX: Why to add the system database if the class is `me'? 327 */ 328 if (_secure_path(path_login_conf, 0, 0) != -1) 329 login_dbarray[i++] = path_login_conf; 330 login_dbarray[i] = NULL; 331 332 if (name == NULL || *name == '\0') 333 name = LOGIN_DEFCLASS; 334 335 switch (cgetent(&lc->lc_cap, login_dbarray, name)) { 336 case -1: /* Failed, entry does not exist */ 337 if (me) 338 break; /* Don't retry default on 'me' */ 339 if (i == 0) 340 r = -1; 341 else if ((r = open(login_dbarray[0], O_RDONLY | O_CLOEXEC)) >= 0) 342 close(r); 343 /* 344 * If there's at least one login class database, 345 * and we aren't searching for a default class 346 * then complain about a non-existent class. 347 */ 348 if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0) 349 syslog(LOG_ERR, "login_getclass: unknown class '%s'", name); 350 /* fall-back to default class */ 351 name = LOGIN_DEFCLASS; 352 msg = "%s: no default/fallback class '%s'"; 353 if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0) 354 break; 355 /* FALLTHROUGH - just return system defaults */ 356 case 0: /* success! */ 357 if ((lc->lc_class = strdup(name)) != NULL) { 358 if (dir) { 359 (void)seteuid(euid); 360 (void)setegid(egid); 361 } 362 ++lc_object_count; 363 return lc; 364 } 365 msg = "%s: strdup: %m"; 366 break; 367 case -2: 368 msg = "%s: retrieving class information: %m"; 369 break; 370 case -3: 371 msg = "%s: 'tc=' reference loop '%s'"; 372 break; 373 case 1: 374 msg = "couldn't resolve 'tc=' reference in '%s'"; 375 break; 376 default: 377 msg = "%s: unexpected cgetent() error '%s': %m"; 378 break; 379 } 380 if (dir) { 381 (void)seteuid(euid); 382 (void)setegid(egid); 383 } 384 if (msg != NULL) 385 syslog(LOG_ERR, msg, "login_getclass", name); 386 free(lc); 387 } 388 389 return NULL; 390} 391 392 393 394/* 395 * login_getclass() 396 * Get the login class for the system (only) login class database. 397 * Return a filled-out login_cap_t structure, including 398 * class name, and the capability record buffer. 399 */ 400 401login_cap_t * 402login_getclass(const char *cls) 403{ 404 return login_getclassbyname(cls, NULL); 405} 406 407 408/* 409 * login_getpwclass() 410 * Get the login class for a given password entry from 411 * the system (only) login class database. 412 * If the password entry's class field is not set, or 413 * the class specified does not exist, then use the 414 * default of LOGIN_DEFCLASS (i.e., "default") for an unprivileged 415 * user or that of LOGIN_DEFROOTCLASS (i.e., "root") for a super-user. 416 * Return a filled-out login_cap_t structure, including 417 * class name, and the capability record buffer. 418 */ 419 420login_cap_t * 421login_getpwclass(const struct passwd *pwd) 422{ 423 const char *cls = NULL; 424 425 if (pwd != NULL) { 426 cls = pwd->pw_class; 427 if (cls == NULL || *cls == '\0') 428 cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; 429 } 430 /* 431 * XXX: pwd should be unused by login_getclassbyname() unless cls is `me', 432 * so NULL can be passed instead of pwd for more safety. 433 */ 434 return login_getclassbyname(cls, pwd); 435} 436 437 438/* 439 * login_getuserclass() 440 * Get the `me' login class, allowing user overrides via ~/.login_conf. 441 * Note that user overrides are allowed only in the `me' class. 442 */ 443 444login_cap_t * 445login_getuserclass(const struct passwd *pwd) 446{ 447 return login_getclassbyname(LOGIN_MECLASS, pwd); 448} 449 450 451/* 452 * login_getcapstr() 453 * Given a login_cap entry, and a capability name, return the 454 * value defined for that capability, a default if not found, or 455 * an error string on error. 456 */ 457 458const char * 459login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error) 460{ 461 char *res; 462 int ret; 463 464 if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0') 465 return def; 466 467 if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1) 468 return def; 469 return (ret >= 0) ? res : error; 470} 471 472 473/* 474 * login_getcaplist() 475 * Given a login_cap entry, and a capability name, return the 476 * value defined for that capability split into an array of 477 * strings. 478 */ 479 480const char ** 481login_getcaplist(login_cap_t *lc, const char *cap, const char *chars) 482{ 483 const char *lstring; 484 485 if (chars == NULL) 486 chars = ", \t"; 487 if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL) 488 return arrayize(lstring, chars, NULL); 489 return NULL; 490} 491 492 493/* 494 * login_getpath() 495 * From the login_cap_t <lc>, get the capability <cap> which is 496 * formatted as either a space or comma delimited list of paths 497 * and append them all into a string and separate by semicolons. 498 * If there is an error of any kind, return <error>. 499 */ 500 501const char * 502login_getpath(login_cap_t *lc, const char *cap, const char *error) 503{ 504 const char *str; 505 char *ptr; 506 int count; 507 508 str = login_getcapstr(lc, cap, NULL, NULL); 509 if (str == NULL) 510 return error; 511 ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */ 512 while (*ptr) { 513 count = strcspn(ptr, ", \t"); 514 ptr += count; 515 if (*ptr) 516 *ptr++ = ':'; 517 } 518 return str; 519} 520 521 522static int 523isinfinite(const char *s) 524{ 525 static const char *infs[] = { 526 "infinity", 527 "inf", 528 "unlimited", 529 "unlimit", 530 "-1", 531 NULL 532 }; 533 const char **i = &infs[0]; 534 535 while (*i != NULL) { 536 if (strcasecmp(s, *i) == 0) 537 return 1; 538 ++i; 539 } 540 return 0; 541} 542 543 544static u_quad_t 545rmultiply(u_quad_t n1, u_quad_t n2) 546{ 547 u_quad_t m, r; 548 int b1, b2; 549 550 static int bpw = 0; 551 552 /* Handle simple cases */ 553 if (n1 == 0 || n2 == 0) 554 return 0; 555 if (n1 == 1) 556 return n2; 557 if (n2 == 1) 558 return n1; 559 560 /* 561 * sizeof() returns number of bytes needed for storage. 562 * This may be different from the actual number of useful bits. 563 */ 564 if (!bpw) { 565 bpw = sizeof(u_quad_t) * 8; 566 while (((u_quad_t)1 << (bpw-1)) == 0) 567 --bpw; 568 } 569 570 /* 571 * First check the magnitude of each number. If the sum of the 572 * magnatude is way to high, reject the number. (If this test 573 * is not done then the first multiply below may overflow.) 574 */ 575 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 576 ; 577 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 578 ; 579 if (b1 + b2 - 2 > bpw) { 580 errno = ERANGE; 581 return (UQUAD_MAX); 582 } 583 584 /* 585 * Decompose the multiplication to be: 586 * h1 = n1 & ~1 587 * h2 = n2 & ~1 588 * l1 = n1 & 1 589 * l2 = n2 & 1 590 * (h1 + l1) * (h2 + l2) 591 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 592 * 593 * Since h1 && h2 do not have the low bit set, we can then say: 594 * 595 * (h1>>1 * h2>>1 * 4) + ... 596 * 597 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 598 * overflow. 599 * 600 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 601 * then adding in residual amout will cause an overflow. 602 */ 603 604 m = (n1 >> 1) * (n2 >> 1); 605 if (m >= ((u_quad_t)1 << (bpw-2))) { 606 errno = ERANGE; 607 return (UQUAD_MAX); 608 } 609 m *= 4; 610 611 r = (n1 & n2 & 1) 612 + (n2 & 1) * (n1 & ~(u_quad_t)1) 613 + (n1 & 1) * (n2 & ~(u_quad_t)1); 614 615 if ((u_quad_t)(m + r) < m) { 616 errno = ERANGE; 617 return (UQUAD_MAX); 618 } 619 m += r; 620 621 return (m); 622} 623 624 625/* 626 * login_getcaptime() 627 * From the login_cap_t <lc>, get the capability <cap>, which is 628 * formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not 629 * present in <lc>, return <def>; if there is an error of some kind, 630 * return <error>. 631 */ 632 633rlim_t 634login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 635{ 636 char *res, *ep, *oval; 637 int r; 638 rlim_t tot; 639 640 errno = 0; 641 if (lc == NULL || lc->lc_cap == NULL) 642 return def; 643 644 /* 645 * Look for <cap> in lc_cap. 646 * If it's not there (-1), return <def>. 647 * If there's an error, return <error>. 648 */ 649 650 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 651 return def; 652 else if (r < 0) 653 return error; 654 655 /* "inf" and "infinity" are special cases */ 656 if (isinfinite(res)) 657 return RLIM_INFINITY; 658 659 /* 660 * Now go through the string, turning something like 1h2m3s into 661 * an integral value. Whee. 662 */ 663 664 errno = 0; 665 tot = 0; 666 oval = res; 667 while (*res) { 668 rlim_t tim = strtoq(res, &ep, 0); 669 rlim_t mult = 1; 670 671 if (ep == NULL || ep == res || errno != 0) { 672 invalid: 673 syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s", 674 lc->lc_class, cap, oval); 675 errno = ERANGE; 676 return error; 677 } 678 /* Look for suffixes */ 679 switch (*ep++) { 680 case 0: 681 ep--; 682 break; /* end of string */ 683 case 's': case 'S': /* seconds */ 684 break; 685 case 'm': case 'M': /* minutes */ 686 mult = 60; 687 break; 688 case 'h': case 'H': /* hours */ 689 mult = 60L * 60L; 690 break; 691 case 'd': case 'D': /* days */ 692 mult = 60L * 60L * 24L; 693 break; 694 case 'w': case 'W': /* weeks */ 695 mult = 60L * 60L * 24L * 7L; 696 break; 697 case 'y': case 'Y': /* 365-day years */ 698 mult = 60L * 60L * 24L * 365L; 699 break; 700 default: 701 goto invalid; 702 } 703 res = ep; 704 tot += rmultiply(tim, mult); 705 if (errno) 706 goto invalid; 707 } 708 709 return tot; 710} 711 712 713/* 714 * login_getcapnum() 715 * From the login_cap_t <lc>, extract the numerical value <cap>. 716 * If it is not present, return <def> for a default, and return 717 * <error> if there is an error. 718 * Like login_getcaptime(), only it only converts to a number, not 719 * to a time; "infinity" and "inf" are 'special.' 720 */ 721 722rlim_t 723login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 724{ 725 char *ep, *res; 726 int r; 727 rlim_t val; 728 729 if (lc == NULL || lc->lc_cap == NULL) 730 return def; 731 732 /* 733 * For BSDI compatibility, try for the tag=<val> first 734 */ 735 r = cgetstr(lc->lc_cap, cap, &res); 736 if (r == -1) { 737 long lval; 738 /* string capability not present, so try for tag#<val> as numeric */ 739 if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1) 740 return def; /* Not there, so return default */ 741 else if (r < 0) 742 return error; 743 else 744 return (rlim_t)lval; 745 } else if (r < 0) 746 return error; 747 748 if (isinfinite(res)) 749 return RLIM_INFINITY; 750 751 errno = 0; 752 val = strtoq(res, &ep, 0); 753 if (ep == NULL || ep == res || errno != 0) { 754 syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s", 755 lc->lc_class, cap, res); 756 errno = ERANGE; 757 return error; 758 } 759 760 return val; 761} 762 763/* 764 * Extract a string capability expected to hold a specific value from a list. 765 * 766 * 'values' must be a NULL-terminated array of strings listing the possible 767 * values. 768 * 769 * A non-negative return code indicates success, and is the index of the value 770 * in 'values' the capability is set to. 771 * 772 * Negative return codes indicate an error: 773 * -4: 'lc' or 'cap' insufficiently initialized or not valid. 774 * -3: System error (allocation failure). 775 * -2: Capability not found or not a string. 776 * -1: Capability has a string value, but not one listed in 'values'. 777 */ 778int 779login_getcapenum(login_cap_t *lc, const char *cap, const char * const *values) 780{ 781 int ret, i; 782 char *cand; 783 const char * const *val; 784 785 if (lc == NULL || lc->lc_cap == NULL || cap == NULL || *cap == '\0') 786 return (-4); 787 788 ret = cgetstr(lc->lc_cap, cap, &cand); 789 790 if (ret == -1) 791 /* Cap not found. */ 792 return (-2); 793 else if (ret < 0) 794 /* System error (normally, allocation failure). */ 795 return (-3); 796 797 ret = -1; 798 799 for (i = 0, val = values; *val != NULL; val++) 800 if (strcmp(cand, *val) == 0) { 801 ret = i; 802 break; 803 } 804 805 free(cand); 806 return (ret); 807} 808 809 810 811/* 812 * login_getcapsize() 813 * From the login_cap_t <lc>, extract the capability <cap>, which is 814 * formatted as a size (e.g., "<cap>=10M"); it can also be "infinity". 815 * If not present, return <def>, or <error> if there is an error of 816 * some sort. 817 */ 818 819rlim_t 820login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error) 821{ 822 char *ep, *res, *oval; 823 int r; 824 rlim_t tot; 825 826 if (lc == NULL || lc->lc_cap == NULL) 827 return def; 828 829 if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) 830 return def; 831 else if (r < 0) 832 return error; 833 834 if (isinfinite(res)) 835 return RLIM_INFINITY; 836 837 errno = 0; 838 tot = 0; 839 oval = res; 840 while (*res) { 841 rlim_t siz = strtoq(res, &ep, 0); 842 rlim_t mult = 1; 843 844 if (ep == NULL || ep == res || errno != 0) { 845 invalid: 846 syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s", 847 lc->lc_class, cap, oval); 848 errno = ERANGE; 849 return error; 850 } 851 switch (*ep++) { 852 case 0: /* end of string */ 853 ep--; 854 break; 855 case 'b': case 'B': /* 512-byte blocks */ 856 mult = 512; 857 break; 858 case 'k': case 'K': /* 1024-byte Kilobytes */ 859 mult = 1024; 860 break; 861 case 'm': case 'M': /* 1024-k kbytes */ 862 mult = 1024 * 1024; 863 break; 864 case 'g': case 'G': /* 1Gbyte */ 865 mult = 1024 * 1024 * 1024; 866 break; 867 case 't': case 'T': /* 1TBte */ 868 mult = 1024LL * 1024LL * 1024LL * 1024LL; 869 break; 870 default: 871 goto invalid; 872 } 873 res = ep; 874 tot += rmultiply(siz, mult); 875 if (errno) 876 goto invalid; 877 } 878 879 return tot; 880} 881 882 883/* 884 * login_getcapbool() 885 * From the login_cap_t <lc>, check for the existence of the capability 886 * of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return 887 * the whether or not <cap> exists there. 888 */ 889 890int 891login_getcapbool(login_cap_t *lc, const char *cap, int def) 892{ 893 if (lc == NULL || lc->lc_cap == NULL) 894 return def; 895 return (cgetcap(lc->lc_cap, cap, ':') != NULL); 896} 897 898 899/* 900 * login_getstyle() 901 * Given a login_cap entry <lc>, and optionally a type of auth <auth>, 902 * and optionally a style <style>, find the style that best suits these 903 * rules: 904 * 1. If <auth> is non-null, look for an "auth-<auth>=" string 905 * in the capability; if not present, default to "auth=". 906 * 2. If there is no auth list found from (1), default to 907 * "passwd" as an authorization list. 908 * 3. If <style> is non-null, look for <style> in the list of 909 * authorization methods found from (2); if <style> is NULL, default 910 * to LOGIN_DEFSTYLE ("passwd"). 911 * 4. If the chosen style is found in the chosen list of authorization 912 * methods, return that; otherwise, return NULL. 913 * E.g.: 914 * login_getstyle(lc, NULL, "ftp"); 915 * login_getstyle(lc, "login", NULL); 916 * login_getstyle(lc, "skey", "network"); 917 */ 918 919const char * 920login_getstyle(login_cap_t *lc, const char *style, const char *auth) 921{ 922 int i; 923 const char **authtypes = NULL; 924 char *auths= NULL; 925 char realauth[64]; 926 927 static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL }; 928 929 if (auth != NULL && *auth != '\0') { 930 if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth)) 931 authtypes = login_getcaplist(lc, realauth, NULL); 932 } 933 934 if (authtypes == NULL) 935 authtypes = login_getcaplist(lc, "auth", NULL); 936 937 if (authtypes == NULL) 938 authtypes = defauthtypes; 939 940 /* 941 * We have at least one authtype now; auths is a comma-separated 942 * (or space-separated) list of authentication types. We have to 943 * convert from this to an array of char*'s; authtypes then gets this. 944 */ 945 i = 0; 946 if (style != NULL && *style != '\0') { 947 while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0) 948 i++; 949 } 950 951 lc->lc_style = NULL; 952 if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL) 953 lc->lc_style = auths; 954 955 if (lc->lc_style != NULL) 956 lc->lc_style = strdup(lc->lc_style); 957 958 return lc->lc_style; 959} 960