1/* $NetBSD: login_cap.c,v 1.33 2015/10/29 20:29:24 kamil Exp $ */ 2 3/*- 4 * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Berkeley Software Design, 17 * Inc. 18 * 4. The name of Berkeley Software Design, Inc. may not be used to endorse 19 * or promote products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp 35 */ 36 37#include <sys/cdefs.h> 38#if defined(LIBC_SCCS) && !defined(lint) 39__RCSID("$NetBSD: login_cap.c,v 1.33 2015/10/29 20:29:24 kamil Exp $"); 40#endif /* LIBC_SCCS and not lint */ 41 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <sys/time.h> 45#include <sys/resource.h> 46#include <sys/param.h> 47 48#include <assert.h> 49#include <ctype.h> 50#include <err.h> 51#include <errno.h> 52#include <fcntl.h> 53#include <limits.h> 54#include <login_cap.h> 55#include <paths.h> 56#include <pwd.h> 57#include <stdio.h> 58#include <stdlib.h> 59#include <string.h> 60#include <syslog.h> 61#include <unistd.h> 62#include <util.h> 63 64static u_quad_t multiply(u_quad_t, u_quad_t); 65static u_quad_t strtolimit(const char *, char **, int); 66static u_quad_t strtosize(const char *, char **, int); 67static int gsetrl(login_cap_t *, int, const char *, int type); 68static int isinfinite(const char *); 69static int envset(void *, const char *, const char *, int); 70 71login_cap_t * 72login_getclass(const char *class) 73{ 74 const char *classfiles[2]; 75 login_cap_t *lc; 76 int res; 77 78 /* class may be NULL */ 79 80 if (secure_path(_PATH_LOGIN_CONF) == 0) { 81 classfiles[0] = _PATH_LOGIN_CONF; 82 classfiles[1] = NULL; 83 } else { 84 classfiles[0] = NULL; 85 } 86 87 if ((lc = malloc(sizeof(login_cap_t))) == NULL) { 88 syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__); 89 return (0); 90 } 91 92 lc->lc_cap = 0; 93 lc->lc_style = 0; 94 95 if (class == NULL || class[0] == '\0') 96 class = LOGIN_DEFCLASS; 97 98 if ((lc->lc_class = strdup(class)) == NULL) { 99 syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__); 100 free(lc); 101 return (0); 102 } 103 104 /* 105 * Not having a login.conf file is not an error condition. 106 * The individual routines deal reasonably with missing 107 * capabilities and use default values. 108 */ 109 if (classfiles[0] == NULL) 110 return(lc); 111 112 if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0) { 113 lc->lc_cap = 0; 114 switch (res) { 115 case 1: 116 syslog(LOG_ERR, "%s: couldn't resolve 'tc'", 117 lc->lc_class); 118 break; 119 case -1: 120 if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == 0) 121 return (lc); 122 syslog(LOG_ERR, "%s: unknown class", lc->lc_class); 123 break; 124 case -2: 125 syslog(LOG_ERR, "%s: getting class information: %m", 126 lc->lc_class); 127 break; 128 case -3: 129 syslog(LOG_ERR, "%s: 'tc' reference loop", 130 lc->lc_class); 131 break; 132 default: 133 syslog(LOG_ERR, "%s: unexpected cgetent error", 134 lc->lc_class); 135 break; 136 } 137 free(lc->lc_class); 138 free(lc); 139 return (0); 140 } 141 return (lc); 142} 143 144login_cap_t * 145login_getpwclass(const struct passwd *pwd) 146{ 147 148 /* pwd may be NULL */ 149 150 return login_getclass(pwd ? pwd->pw_class : NULL); 151} 152 153char * 154login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *e) 155{ 156 char *res = NULL; 157 int status; 158 159 errno = 0; 160 161 _DIAGASSERT(cap != NULL); 162 163 if (!lc || !lc->lc_cap) 164 return (def); 165 166 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 167 case -1: 168 if (res) 169 free(res); 170 return (def); 171 case -2: 172 syslog(LOG_ERR, "%s: getting capability %s: %m", 173 lc->lc_class, cap); 174 if (res) 175 free(res); 176 return (e); 177 default: 178 if (status >= 0) 179 return (res); 180 syslog(LOG_ERR, "%s: unexpected error with capability %s", 181 lc->lc_class, cap); 182 if (res) 183 free(res); 184 return (e); 185 } 186} 187 188quad_t 189login_getcaptime(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 190{ 191 char *ep; 192 char *res = NULL, *sres; 193 int status; 194 quad_t q, r; 195 196 _DIAGASSERT(cap != NULL); 197 198 errno = 0; 199 if (!lc || !lc->lc_cap) 200 return (def); 201 202 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 203 case -1: 204 if (res) 205 free(res); 206 return (def); 207 case -2: 208 syslog(LOG_ERR, "%s: getting capability %s: %m", 209 lc->lc_class, cap); 210 errno = ERANGE; 211 if (res) 212 free(res); 213 return (e); 214 default: 215 if (status >= 0) 216 break; 217 syslog(LOG_ERR, "%s: unexpected error with capability %s", 218 lc->lc_class, cap); 219 errno = ERANGE; 220 if (res) 221 free(res); 222 return (e); 223 } 224 225 if (isinfinite(res)) 226 return (RLIM_INFINITY); 227 228 errno = 0; 229 230 q = 0; 231 sres = res; 232 while (*res) { 233 r = strtoq(res, &ep, 0); 234 if (!ep || ep == res || 235 ((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) { 236invalid: 237 syslog(LOG_ERR, "%s:%s=%s: invalid time", 238 lc->lc_class, cap, sres); 239 errno = ERANGE; 240 free(sres); 241 return (e); 242 } 243 switch (*ep++) { 244 case '\0': 245 --ep; 246 break; 247 case 's': case 'S': 248 break; 249 case 'm': case 'M': 250 r *= 60; 251 break; 252 case 'h': case 'H': 253 r *= 60 * 60; 254 break; 255 case 'd': case 'D': 256 r *= 60 * 60 * 24; 257 break; 258 case 'w': case 'W': 259 r *= 60 * 60 * 24 * 7; 260 break; 261 case 'y': case 'Y': /* Pretty absurd */ 262 r *= 60 * 60 * 24 * 365; 263 break; 264 default: 265 goto invalid; 266 } 267 res = ep; 268 q += r; 269 } 270 free(sres); 271 return (q); 272} 273 274quad_t 275login_getcapnum(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 276{ 277 char *ep; 278 char *res = NULL; 279 int status; 280 quad_t q; 281 282 _DIAGASSERT(cap != NULL); 283 284 errno = 0; 285 if (!lc || !lc->lc_cap) 286 return (def); 287 288 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 289 case -1: 290 if (res) 291 free(res); 292 return (def); 293 case -2: 294 syslog(LOG_ERR, "%s: getting capability %s: %m", 295 lc->lc_class, cap); 296 errno = ERANGE; 297 if (res) 298 free(res); 299 return (e); 300 default: 301 if (status >= 0) 302 break; 303 syslog(LOG_ERR, "%s: unexpected error with capability %s", 304 lc->lc_class, cap); 305 errno = ERANGE; 306 if (res) 307 free(res); 308 return (e); 309 } 310 311 if (isinfinite(res)) 312 return (RLIM_INFINITY); 313 314 errno = 0; 315 q = strtoq(res, &ep, 0); 316 if (!ep || ep == res || ep[0] || 317 ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 318 syslog(LOG_ERR, "%s:%s=%s: invalid number", 319 lc->lc_class, cap, res); 320 errno = ERANGE; 321 free(res); 322 return (e); 323 } 324 free(res); 325 return (q); 326} 327 328quad_t 329login_getcapsize(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 330{ 331 char *ep; 332 char *res = NULL; 333 int status; 334 quad_t q; 335 336 _DIAGASSERT(cap != NULL); 337 338 errno = 0; 339 340 if (!lc || !lc->lc_cap) 341 return (def); 342 343 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 344 case -1: 345 if (res) 346 free(res); 347 return (def); 348 case -2: 349 syslog(LOG_ERR, "%s: getting capability %s: %m", 350 lc->lc_class, cap); 351 errno = ERANGE; 352 if (res) 353 free(res); 354 return (e); 355 default: 356 if (status >= 0) 357 break; 358 syslog(LOG_ERR, "%s: unexpected error with capability %s", 359 lc->lc_class, cap); 360 errno = ERANGE; 361 if (res) 362 free(res); 363 return (e); 364 } 365 366 errno = 0; 367 q = strtolimit(res, &ep, 0); 368 if (!ep || ep == res || (ep[0] && ep[1]) || 369 ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 370 syslog(LOG_ERR, "%s:%s=%s: invalid size", 371 lc->lc_class, cap, res); 372 errno = ERANGE; 373 free(res); 374 return (e); 375 } 376 free(res); 377 return (q); 378} 379 380int 381login_getcapbool(login_cap_t *lc, const char *cap, u_int def) 382{ 383 384 _DIAGASSERT(cap != NULL); 385 386 if (!lc || !lc->lc_cap) 387 return (def); 388 389 return (cgetcap(lc->lc_cap, cap, ':') != NULL); 390} 391 392void 393login_close(login_cap_t *lc) 394{ 395 396 if (lc) { 397 if (lc->lc_class) 398 free(lc->lc_class); 399 if (lc->lc_cap) 400 free(lc->lc_cap); 401 if (lc->lc_style) 402 free(lc->lc_style); 403 free(lc); 404 } 405} 406 407#define R_CTIME 1 408#define R_CSIZE 2 409#define R_CNUMB 3 410 411static struct { 412 int what; 413 int type; 414 const char *name; 415} r_list[] = { 416 { RLIMIT_CPU, R_CTIME, "cputime", }, 417 { RLIMIT_FSIZE, R_CSIZE, "filesize", }, 418 { RLIMIT_DATA, R_CSIZE, "datasize", }, 419 { RLIMIT_STACK, R_CSIZE, "stacksize", }, 420 { RLIMIT_RSS, R_CSIZE, "memoryuse", }, 421 { RLIMIT_MEMLOCK, R_CSIZE, "memorylocked", }, 422 { RLIMIT_NPROC, R_CNUMB, "maxproc", }, 423 { RLIMIT_NTHR, R_CNUMB, "maxthread", }, 424 { RLIMIT_NOFILE, R_CNUMB, "openfiles", }, 425 { RLIMIT_CORE, R_CSIZE, "coredumpsize", }, 426 { RLIMIT_SBSIZE, R_CSIZE, "sbsize", }, 427 { RLIMIT_AS, R_CSIZE, "vmemoryuse", }, 428 { -1, 0, 0 } 429}; 430 431static int 432gsetrl(login_cap_t *lc, int what, const char *name, int type) 433{ 434 struct rlimit rl; 435 struct rlimit r; 436 char name_cur[32]; 437 char name_max[32]; 438 439 _DIAGASSERT(name != NULL); 440 441 (void)snprintf(name_cur, sizeof(name_cur), "%s-cur", name); 442 (void)snprintf(name_max, sizeof(name_max), "%s-max", name); 443 444 if (getrlimit(what, &r)) { 445 syslog(LOG_ERR, "getting resource limit: %m"); 446 return (-1); 447 } 448 449#define RCUR ((quad_t)r.rlim_cur) 450#define RMAX ((quad_t)r.rlim_max) 451 452 switch (type) { 453 case R_CTIME: 454 r.rlim_cur = login_getcaptime(lc, name, RCUR, RCUR); 455 r.rlim_max = login_getcaptime(lc, name, RMAX, RMAX); 456 rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR); 457 rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX); 458 break; 459 case R_CSIZE: 460 r.rlim_cur = login_getcapsize(lc, name, RCUR, RCUR); 461 r.rlim_max = login_getcapsize(lc, name, RMAX, RMAX); 462 rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR); 463 rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX); 464 break; 465 case R_CNUMB: 466 r.rlim_cur = login_getcapnum(lc, name, RCUR, RCUR); 467 r.rlim_max = login_getcapnum(lc, name, RMAX, RMAX); 468 rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR); 469 rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX); 470 break; 471 default: 472 syslog(LOG_ERR, "%s: invalid type %d setting resource limit %s", 473 lc->lc_class, type, name); 474 return (-1); 475 } 476 477 if (setrlimit(what, &rl)) { 478 syslog(LOG_ERR, "%s: setting resource limit %s: %m", 479 lc->lc_class, name); 480 return (-1); 481 } 482#undef RCUR 483#undef RMAX 484 return (0); 485} 486 487static int 488/*ARGSUSED*/ 489envset(void *envp __unused, const char *name, const char *value, int overwrite) 490{ 491 return setenv(name, value, overwrite); 492} 493 494int 495setuserenv(login_cap_t *lc, envfunc_t senv, void *envp) 496{ 497 const char *stop = ", \t"; 498 size_t i, count; 499 char *ptr; 500 char **res; 501 char *str = login_getcapstr(lc, "setenv", NULL, NULL); 502 503 if (str == NULL || *str == '\0') 504 return 0; 505 506 /* 507 * count the sub-strings, this may over-count since we don't 508 * account for escaped delimiters. 509 */ 510 for (i = 1, ptr = str; *ptr; i++) { 511 ptr += strcspn(ptr, stop); 512 if (*ptr) 513 ptr++; 514 } 515 516 /* allocate ptr array and string */ 517 count = i; 518 res = malloc(count * sizeof(*res) + strlen(str) + 1); 519 520 if (!res) 521 return -1; 522 523 ptr = (char *)(void *)&res[count]; 524 (void)strcpy(ptr, str); 525 526 /* split string */ 527 for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; ) 528 if (*res[i]) 529 i++; 530 531 count = i; 532 533 for (i = 0; i < count; i++) { 534 if ((ptr = strchr(res[i], '=')) != NULL) 535 *ptr++ = '\0'; 536 else 537 ptr = NULL; 538 (void)(*senv)(envp, res[i], ptr ? ptr : "", 1); 539 } 540 541 free(res); 542 return 0; 543} 544 545int 546setclasscontext(const char *class, u_int flags) 547{ 548 int ret; 549 login_cap_t *lc; 550 551 flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK | 552 LOGIN_SETPATH; 553 554 lc = login_getclass(class); 555 ret = lc ? setusercontext(lc, NULL, 0, flags) : -1; 556 login_close(lc); 557 return (ret); 558} 559 560int 561setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) 562{ 563 char per_user_tmp[MAXPATHLEN + 1]; 564 const char *component_name; 565 login_cap_t *flc; 566 quad_t p; 567 int i; 568 ssize_t len; 569 570 flc = NULL; 571 572 if (!lc) 573 flc = lc = login_getclass(pwd ? pwd->pw_class : NULL); 574 575 /* 576 * Without the pwd entry being passed we cannot set either 577 * the group or the login. We could complain about it. 578 */ 579 if (pwd == NULL) 580 flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN); 581 582#ifdef LOGIN_OSETGROUP 583 if (pwd == NULL) 584 flags &= ~LOGIN_OSETGROUP; 585 if (flags & LOGIN_OSETGROUP) 586 flags = (flags & ~LOGIN_OSETGROUP) | LOGIN_SETGROUP; 587#endif 588 if (flags & LOGIN_SETRESOURCES) 589 for (i = 0; r_list[i].name; ++i) 590 (void)gsetrl(lc, r_list[i].what, r_list[i].name, 591 r_list[i].type); 592 593 if (flags & LOGIN_SETPRIORITY) { 594 p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0); 595 596 if (setpriority(PRIO_PROCESS, 0, (int)p) == -1) 597 syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class); 598 } 599 600 if (flags & LOGIN_SETUMASK) { 601 p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK, 602 (quad_t)LOGIN_DEFUMASK); 603 umask((mode_t)p); 604 } 605 606 if (flags & LOGIN_SETGID) { 607 if (setgid(pwd->pw_gid) == -1) { 608 syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid); 609 login_close(flc); 610 return (-1); 611 } 612 } 613 614 if (flags & LOGIN_SETGROUPS) { 615 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 616 syslog(LOG_ERR, "initgroups(%s,%d): %m", 617 pwd->pw_name, pwd->pw_gid); 618 login_close(flc); 619 return (-1); 620 } 621 } 622 623 /* Create per-user temporary directories if needed. */ 624 if ((len = readlink("/tmp", per_user_tmp, 625 sizeof(per_user_tmp) - 6)) != -1) { 626 627 static const char atuid[] = "/@ruid"; 628 char *lp; 629 630 /* readlink does not nul-terminate the string */ 631 per_user_tmp[len] = '\0'; 632 633 /* Check if it's magic symlink. */ 634 lp = strstr(per_user_tmp, atuid); 635 if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') { 636 lp++; 637 638 if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) { 639 syslog(LOG_ERR, "real temporary path too long"); 640 login_close(flc); 641 return (-1); 642 } 643 if (mkdir(per_user_tmp, S_IRWXU) != -1) { 644 if (chown(per_user_tmp, pwd->pw_uid, 645 pwd->pw_gid)) { 646 component_name = "chown"; 647 goto out; 648 } 649 650 /* 651 * Must set sticky bit for tmp directory, some 652 * programs rely on this. 653 */ 654 if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) { 655 component_name = "chmod"; 656 goto out; 657 } 658 } else { 659 if (errno != EEXIST) { 660 component_name = "mkdir"; 661 goto out; 662 } else { 663 /* 664 * We must ensure that we own the 665 * directory and that is has the correct 666 * permissions, otherwise a DOS attack 667 * is possible. 668 */ 669 struct stat sb; 670 if (stat(per_user_tmp, &sb) == -1) { 671 component_name = "stat"; 672 goto out; 673 } 674 675 if (sb.st_uid != pwd->pw_uid) { 676 if (chown(per_user_tmp, 677 pwd->pw_uid, pwd->pw_gid)) { 678 component_name = "chown"; 679 goto out; 680 } 681 } 682 683 if (sb.st_mode != (S_IRWXU | S_ISVTX)) { 684 if (chmod(per_user_tmp, 685 S_IRWXU | S_ISVTX)) { 686 component_name = "chmod"; 687 goto out; 688 } 689 } 690 } 691 } 692 } 693 } 694 errno = 0; 695 696 if (flags & LOGIN_SETLOGIN) 697 if (setlogin(pwd->pw_name) == -1) { 698 syslog(LOG_ERR, "setlogin(%s) failure: %m", 699 pwd->pw_name); 700 login_close(flc); 701 return (-1); 702 } 703 704 if (flags & LOGIN_SETUSER) 705 if (setuid(uid) == -1) { 706 syslog(LOG_ERR, "setuid(%d): %m", uid); 707 login_close(flc); 708 return (-1); 709 } 710 711 if (flags & LOGIN_SETENV) 712 setuserenv(lc, envset, NULL); 713 714 if (flags & LOGIN_SETPATH) 715 setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL); 716 717 login_close(flc); 718 return (0); 719 720out: 721 if (component_name != NULL) { 722 syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp); 723 login_close(flc); 724 return (-1); 725 } else { 726 syslog(LOG_ERR, "%s: %m", per_user_tmp); 727 login_close(flc); 728 return (-1); 729 } 730} 731 732void 733setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp) 734{ 735 size_t hlen, plen; 736 int cnt = 0; 737 char *path; 738 const char *cpath; 739 char *p, *q; 740 741 _DIAGASSERT(home != NULL); 742 743 hlen = strlen(home); 744 745 p = path = login_getcapstr(lc, "path", NULL, NULL); 746 if (p) { 747 while (*p) 748 if (*p++ == '~') 749 ++cnt; 750 plen = (p - path) + cnt * (hlen + 1) + 1; 751 p = path; 752 q = path = malloc(plen); 753 if (q) { 754 while (*p) { 755 p += strspn(p, " \t"); 756 if (*p == '\0') 757 break; 758 plen = strcspn(p, " \t"); 759 if (hlen == 0 && *p == '~') { 760 p += plen; 761 continue; 762 } 763 if (q != path) 764 *q++ = ':'; 765 if (*p == '~') { 766 strcpy(q, home); 767 q += hlen; 768 ++p; 769 --plen; 770 } 771 memcpy(q, p, plen); 772 p += plen; 773 q += plen; 774 } 775 *q = '\0'; 776 cpath = path; 777 } else 778 cpath = _PATH_DEFPATH; 779 } else 780 cpath = _PATH_DEFPATH; 781 if ((*senv)(envp, "PATH", cpath, 1)) 782 warn("could not set PATH"); 783} 784 785/* 786 * Convert an expression of the following forms 787 * 1) A number. 788 * 2) A number followed by a b (mult by 512). 789 * 3) A number followed by a k (mult by 1024). 790 * 5) A number followed by a m (mult by 1024 * 1024). 791 * 6) A number followed by a g (mult by 1024 * 1024 * 1024). 792 * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024). 793 * 8) Two or more numbers (with/without k,b,m,g, or t). 794 * separated by x (also * for backwards compatibility), specifying 795 * the product of the indicated values. 796 */ 797static u_quad_t 798strtosize(const char *str, char **endptr, int radix) 799{ 800 u_quad_t num, num2; 801 char *expr, *expr2; 802 803 _DIAGASSERT(str != NULL); 804 /* endptr may be NULL */ 805 806 errno = 0; 807 num = strtouq(str, &expr, radix); 808 if (errno || expr == str) { 809 if (endptr) 810 *endptr = expr; 811 return (num); 812 } 813 814 switch(*expr) { 815 case 'b': case 'B': 816 num = multiply(num, (u_quad_t)512); 817 ++expr; 818 break; 819 case 'k': case 'K': 820 num = multiply(num, (u_quad_t)1024); 821 ++expr; 822 break; 823 case 'm': case 'M': 824 num = multiply(num, (u_quad_t)1024 * 1024); 825 ++expr; 826 break; 827 case 'g': case 'G': 828 num = multiply(num, (u_quad_t)1024 * 1024 * 1024); 829 ++expr; 830 break; 831 case 't': case 'T': 832 num = multiply(num, (u_quad_t)1024 * 1024); 833 num = multiply(num, (u_quad_t)1024 * 1024); 834 ++expr; 835 break; 836 } 837 838 if (errno) 839 goto erange; 840 841 switch(*expr) { 842 case '*': /* Backward compatible. */ 843 case 'x': 844 num2 = strtosize(expr+1, &expr2, radix); 845 if (errno) { 846 expr = expr2; 847 goto erange; 848 } 849 850 if (expr2 == expr + 1) { 851 if (endptr) 852 *endptr = expr; 853 return (num); 854 } 855 expr = expr2; 856 num = multiply(num, num2); 857 if (errno) 858 goto erange; 859 break; 860 } 861 if (endptr) 862 *endptr = expr; 863 return (num); 864erange: 865 if (endptr) 866 *endptr = expr; 867 errno = ERANGE; 868 return (UQUAD_MAX); 869} 870 871static u_quad_t 872strtolimit(const char *str, char **endptr, int radix) 873{ 874 875 _DIAGASSERT(str != NULL); 876 /* endptr may be NULL */ 877 878 if (isinfinite(str)) { 879 if (endptr) 880 *endptr = (char *)__UNCONST(str) + strlen(str); 881 return ((u_quad_t)RLIM_INFINITY); 882 } 883 return (strtosize(str, endptr, radix)); 884} 885 886static int 887isinfinite(const char *s) 888{ 889 static const char *infs[] = { 890 "infinity", 891 "inf", 892 "unlimited", 893 "unlimit", 894 NULL 895 }; 896 const char **i; 897 898 _DIAGASSERT(s != NULL); 899 900 for (i = infs; *i; i++) { 901 if (!strcasecmp(s, *i)) 902 return 1; 903 } 904 return 0; 905} 906 907static u_quad_t 908multiply(u_quad_t n1, u_quad_t n2) 909{ 910 static int bpw = 0; 911 u_quad_t m; 912 u_quad_t r; 913 int b1, b2; 914 915 /* 916 * Get rid of the simple cases 917 */ 918 if (n1 == 0 || n2 == 0) 919 return (0); 920 if (n1 == 1) 921 return (n2); 922 if (n2 == 1) 923 return (n1); 924 925 /* 926 * sizeof() returns number of bytes needed for storage. 927 * This may be different from the actual number of useful bits. 928 */ 929 if (!bpw) { 930 bpw = sizeof(u_quad_t) * 8; 931 while (((u_quad_t)1 << (bpw-1)) == 0) 932 --bpw; 933 } 934 935 /* 936 * First check the magnitude of each number. If the sum of the 937 * magnitude is to high, reject the number. (If this test 938 * is not done then the first multiply below may overflow.) 939 */ 940 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 941 ; 942 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 943 ; 944 if (b1 + b2 - 2 > bpw) { 945 errno = ERANGE; 946 return (UQUAD_MAX); 947 } 948 949 /* 950 * Decompose the multiplication to be: 951 * h1 = n1 & ~1 952 * h2 = n2 & ~1 953 * l1 = n1 & 1 954 * l2 = n2 & 1 955 * (h1 + l1) * (h2 + l2) 956 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 957 * 958 * Since h1 && h2 do not have the low bit set, we can then say: 959 * 960 * (h1>>1 * h2>>1 * 4) + ... 961 * 962 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 963 * overflow. 964 * 965 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 966 * then adding in residual amount will cause an overflow. 967 */ 968 969 m = (n1 >> 1) * (n2 >> 1); 970 971 if (m >= ((u_quad_t)1 << (bpw-2))) { 972 errno = ERANGE; 973 return (UQUAD_MAX); 974 } 975 976 m *= 4; 977 978 r = (n1 & n2 & 1) 979 + (n2 & 1) * (n1 & ~(u_quad_t)1) 980 + (n1 & 1) * (n2 & ~(u_quad_t)1); 981 982 if ((u_quad_t)(m + r) < m) { 983 errno = ERANGE; 984 return (UQUAD_MAX); 985 } 986 m += r; 987 988 return (m); 989} 990