1 /* $NetBSD: login_cap.c,v 1.29 2007/12/04 22:09:02 mjf 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.29 2007/12/04 22:09:02 mjf 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 64 static u_quad_t multiply(u_quad_t, u_quad_t); 65 static u_quad_t strtolimit(const char *, char **, int); 66 static u_quad_t strtosize(const char *, char **, int); 67 static int gsetrl(login_cap_t *, int, const char *, int type); 68 static int isinfinite(const char *); 69 static int envset(void *, const char *, const char *, int); 70 71 login_cap_t * 72 login_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 144 login_cap_t * 145 login_getpwclass(const struct passwd *pwd) 146 { 147 148 /* pwd may be NULL */ 149 150 return login_getclass(pwd ? pwd->pw_class : NULL); 151 } 152 153 char * 154 login_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 188 quad_t 189 login_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)) { 236 invalid: 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 274 quad_t 275 login_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 328 quad_t 329 login_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 380 int 381 login_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 392 void 393 login_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 411 static 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_NOFILE, R_CNUMB, "openfiles", }, 424 { RLIMIT_CORE, R_CSIZE, "coredumpsize", }, 425 { RLIMIT_SBSIZE, R_CSIZE, "sbsize", }, 426 { -1, 0, 0 } 427 }; 428 429 static int 430 gsetrl(login_cap_t *lc, int what, const char *name, int type) 431 { 432 struct rlimit rl; 433 struct rlimit r; 434 char name_cur[32]; 435 char name_max[32]; 436 437 _DIAGASSERT(name != NULL); 438 439 (void)snprintf(name_cur, sizeof(name_cur), "%s-cur", name); 440 (void)snprintf(name_max, sizeof(name_max), "%s-max", name); 441 442 if (getrlimit(what, &r)) { 443 syslog(LOG_ERR, "getting resource limit: %m"); 444 return (-1); 445 } 446 447 #define RCUR r.rlim_cur 448 #define RMAX r.rlim_max 449 450 switch (type) { 451 case R_CTIME: 452 RCUR = login_getcaptime(lc, name, RCUR, RCUR); 453 RMAX = login_getcaptime(lc, name, RMAX, RMAX); 454 rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR); 455 rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX); 456 break; 457 case R_CSIZE: 458 RCUR = login_getcapsize(lc, name, RCUR, RCUR); 459 RMAX = login_getcapsize(lc, name, RMAX, RMAX); 460 rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR); 461 rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX); 462 break; 463 case R_CNUMB: 464 RCUR = login_getcapnum(lc, name, RCUR, RCUR); 465 RMAX = login_getcapnum(lc, name, RMAX, RMAX); 466 rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR); 467 rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX); 468 break; 469 default: 470 syslog(LOG_ERR, "%s: invalid type %d setting resource limit %s", 471 lc->lc_class, type, name); 472 return (-1); 473 } 474 475 if (setrlimit(what, &rl)) { 476 syslog(LOG_ERR, "%s: setting resource limit %s: %m", 477 lc->lc_class, name); 478 return (-1); 479 } 480 #undef RCUR 481 #undef RMAX 482 return (0); 483 } 484 485 static int 486 /*ARGSUSED*/ 487 envset(void *envp __unused, const char *name, const char *value, int overwrite) 488 { 489 return setenv(name, value, overwrite); 490 } 491 492 int 493 setuserenv(login_cap_t *lc, envfunc_t senv, void *envp) 494 { 495 const char *stop = ", \t"; 496 size_t i, count; 497 char *ptr; 498 char **res; 499 char *str = login_getcapstr(lc, "setenv", NULL, NULL); 500 501 if (str == NULL || *str == '\0') 502 return 0; 503 504 /* 505 * count the sub-strings, this may over-count since we don't 506 * account for escaped delimiters. 507 */ 508 for (i = 1, ptr = str; *ptr; i++) { 509 ptr += strcspn(ptr, stop); 510 if (*ptr) 511 ptr++; 512 } 513 514 /* allocate ptr array and string */ 515 count = i; 516 res = malloc(count * sizeof(char *) + strlen(str) + 1); 517 518 if (!res) 519 return -1; 520 521 ptr = (char *)(void *)&res[count]; 522 (void)strcpy(ptr, str); 523 524 /* split string */ 525 for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; ) 526 if (*res[i]) 527 i++; 528 529 count = i; 530 531 for (i = 0; i < count; i++) { 532 if ((ptr = strchr(res[i], '=')) != NULL) 533 *ptr++ = '\0'; 534 else 535 ptr = NULL; 536 (void)(*senv)(envp, res[i], ptr ? ptr : "", 1); 537 } 538 539 free(res); 540 return 0; 541 } 542 543 int 544 setclasscontext(const char *class, u_int flags) 545 { 546 int ret; 547 login_cap_t *lc; 548 549 flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK | 550 LOGIN_SETPATH; 551 552 lc = login_getclass(class); 553 ret = lc ? setusercontext(lc, NULL, 0, flags) : -1; 554 login_close(lc); 555 return (ret); 556 } 557 558 int 559 setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) 560 { 561 char per_user_tmp[MAXPATHLEN + 1]; 562 const char *component_name; 563 login_cap_t *flc; 564 quad_t p; 565 int i; 566 ssize_t len; 567 568 flc = NULL; 569 570 if (!lc) 571 flc = lc = login_getclass(pwd ? pwd->pw_class : NULL); 572 573 /* 574 * Without the pwd entry being passed we cannot set either 575 * the group or the login. We could complain about it. 576 */ 577 if (pwd == NULL) 578 flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN); 579 580 #ifdef LOGIN_OSETGROUP 581 if (pwd == NULL) 582 flags &= ~LOGIN_OSETGROUP; 583 if (flags & LOGIN_OSETGROUP) 584 flags = (flags & ~LOGIN_OSETGROUP) | LOGIN_SETGROUP; 585 #endif 586 if (flags & LOGIN_SETRESOURCES) 587 for (i = 0; r_list[i].name; ++i) 588 (void)gsetrl(lc, r_list[i].what, r_list[i].name, 589 r_list[i].type); 590 591 if (flags & LOGIN_SETPRIORITY) { 592 p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0); 593 594 if (setpriority(PRIO_PROCESS, 0, (int)p) == -1) 595 syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class); 596 } 597 598 if (flags & LOGIN_SETUMASK) { 599 p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK, 600 (quad_t)LOGIN_DEFUMASK); 601 umask((mode_t)p); 602 } 603 604 if (flags & LOGIN_SETGID) { 605 if (setgid(pwd->pw_gid) == -1) { 606 syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid); 607 login_close(flc); 608 return (-1); 609 } 610 } 611 612 if (flags & LOGIN_SETGROUPS) { 613 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 614 syslog(LOG_ERR, "initgroups(%s,%d): %m", 615 pwd->pw_name, pwd->pw_gid); 616 login_close(flc); 617 return (-1); 618 } 619 } 620 621 /* Create per-user temporary directories if needed. */ 622 if ((len = readlink("/tmp", per_user_tmp, 623 sizeof(per_user_tmp) - 6)) != -1) { 624 625 static const char atuid[] = "/@ruid"; 626 char *lp; 627 628 /* readlink does not nul-terminate the string */ 629 per_user_tmp[len] = '\0'; 630 631 /* Check if it's magic symlink. */ 632 lp = strstr(per_user_tmp, atuid); 633 if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') { 634 lp++; 635 636 if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) { 637 syslog(LOG_ERR, "real temporary path too long"); 638 login_close(flc); 639 return (-1); 640 } 641 if (mkdir(per_user_tmp, S_IRWXU) != -1) { 642 if (chown(per_user_tmp, pwd->pw_uid, 643 pwd->pw_gid)) { 644 component_name = "chown"; 645 goto out; 646 } 647 648 /* 649 * Must set sticky bit for tmp directory, some 650 * programs rely on this. 651 */ 652 if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) { 653 component_name = "chmod"; 654 goto out; 655 } 656 } else { 657 if (errno != EEXIST) { 658 component_name = "mkdir"; 659 goto out; 660 } else { 661 /* 662 * We must ensure that we own the 663 * directory and that is has the correct 664 * permissions, otherwise a DOS attack 665 * is possible. 666 */ 667 struct stat sb; 668 if (stat(per_user_tmp, &sb) == -1) { 669 component_name = "stat"; 670 goto out; 671 } 672 673 if (sb.st_uid != pwd->pw_uid) { 674 if (chown(per_user_tmp, 675 pwd->pw_uid, pwd->pw_gid)) { 676 component_name = "chown"; 677 goto out; 678 } 679 } 680 681 if (sb.st_mode != (S_IRWXU | S_ISVTX)) { 682 if (chmod(per_user_tmp, 683 S_IRWXU | S_ISVTX)) { 684 component_name = "chmod"; 685 goto out; 686 } 687 } 688 } 689 } 690 } 691 } 692 errno = 0; 693 694 if (flags & LOGIN_SETLOGIN) 695 if (setlogin(pwd->pw_name) == -1) { 696 syslog(LOG_ERR, "setlogin(%s) failure: %m", 697 pwd->pw_name); 698 login_close(flc); 699 return (-1); 700 } 701 702 if (flags & LOGIN_SETUSER) 703 if (setuid(uid) == -1) { 704 syslog(LOG_ERR, "setuid(%d): %m", uid); 705 login_close(flc); 706 return (-1); 707 } 708 709 if (flags & LOGIN_SETENV) 710 setuserenv(lc, envset, NULL); 711 712 if (flags & LOGIN_SETPATH) 713 setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL); 714 715 login_close(flc); 716 return (0); 717 718 out: 719 if (component_name != NULL) { 720 syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp); 721 login_close(flc); 722 return (-1); 723 } else { 724 syslog(LOG_ERR, "%s: %m", per_user_tmp); 725 login_close(flc); 726 return (-1); 727 } 728 } 729 730 void 731 setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp) 732 { 733 size_t hlen, plen; 734 int cnt = 0; 735 char *path; 736 const char *cpath; 737 char *p, *q; 738 739 _DIAGASSERT(home != NULL); 740 741 hlen = strlen(home); 742 743 p = path = login_getcapstr(lc, "path", NULL, NULL); 744 if (p) { 745 while (*p) 746 if (*p++ == '~') 747 ++cnt; 748 plen = (p - path) + cnt * (hlen + 1) + 1; 749 p = path; 750 q = path = malloc(plen); 751 if (q) { 752 while (*p) { 753 p += strspn(p, " \t"); 754 if (*p == '\0') 755 break; 756 plen = strcspn(p, " \t"); 757 if (hlen == 0 && *p == '~') { 758 p += plen; 759 continue; 760 } 761 if (q != path) 762 *q++ = ':'; 763 if (*p == '~') { 764 strcpy(q, home); 765 q += hlen; 766 ++p; 767 --plen; 768 } 769 memcpy(q, p, plen); 770 p += plen; 771 q += plen; 772 } 773 *q = '\0'; 774 cpath = path; 775 } else 776 cpath = _PATH_DEFPATH; 777 } else 778 cpath = _PATH_DEFPATH; 779 if ((*senv)(envp, "PATH", cpath, 1)) 780 warn("could not set PATH"); 781 } 782 783 /* 784 * Convert an expression of the following forms 785 * 1) A number. 786 * 2) A number followed by a b (mult by 512). 787 * 3) A number followed by a k (mult by 1024). 788 * 5) A number followed by a m (mult by 1024 * 1024). 789 * 6) A number followed by a g (mult by 1024 * 1024 * 1024). 790 * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024). 791 * 8) Two or more numbers (with/without k,b,m,g, or t). 792 * separated by x (also * for backwards compatibility), specifying 793 * the product of the indicated values. 794 */ 795 static u_quad_t 796 strtosize(const char *str, char **endptr, int radix) 797 { 798 u_quad_t num, num2; 799 char *expr, *expr2; 800 801 _DIAGASSERT(str != NULL); 802 /* endptr may be NULL */ 803 804 errno = 0; 805 num = strtouq(str, &expr, radix); 806 if (errno || expr == str) { 807 if (endptr) 808 *endptr = expr; 809 return (num); 810 } 811 812 switch(*expr) { 813 case 'b': case 'B': 814 num = multiply(num, (u_quad_t)512); 815 ++expr; 816 break; 817 case 'k': case 'K': 818 num = multiply(num, (u_quad_t)1024); 819 ++expr; 820 break; 821 case 'm': case 'M': 822 num = multiply(num, (u_quad_t)1024 * 1024); 823 ++expr; 824 break; 825 case 'g': case 'G': 826 num = multiply(num, (u_quad_t)1024 * 1024 * 1024); 827 ++expr; 828 break; 829 case 't': case 'T': 830 num = multiply(num, (u_quad_t)1024 * 1024); 831 num = multiply(num, (u_quad_t)1024 * 1024); 832 ++expr; 833 break; 834 } 835 836 if (errno) 837 goto erange; 838 839 switch(*expr) { 840 case '*': /* Backward compatible. */ 841 case 'x': 842 num2 = strtosize(expr+1, &expr2, radix); 843 if (errno) { 844 expr = expr2; 845 goto erange; 846 } 847 848 if (expr2 == expr + 1) { 849 if (endptr) 850 *endptr = expr; 851 return (num); 852 } 853 expr = expr2; 854 num = multiply(num, num2); 855 if (errno) 856 goto erange; 857 break; 858 } 859 if (endptr) 860 *endptr = expr; 861 return (num); 862 erange: 863 if (endptr) 864 *endptr = expr; 865 errno = ERANGE; 866 return (UQUAD_MAX); 867 } 868 869 static u_quad_t 870 strtolimit(const char *str, char **endptr, int radix) 871 { 872 873 _DIAGASSERT(str != NULL); 874 /* endptr may be NULL */ 875 876 if (isinfinite(str)) { 877 if (endptr) 878 *endptr = (char *)__UNCONST(str) + strlen(str); 879 return ((u_quad_t)RLIM_INFINITY); 880 } 881 return (strtosize(str, endptr, radix)); 882 } 883 884 static int 885 isinfinite(const char *s) 886 { 887 static const char *infs[] = { 888 "infinity", 889 "inf", 890 "unlimited", 891 "unlimit", 892 NULL 893 }; 894 const char **i; 895 896 _DIAGASSERT(s != NULL); 897 898 for (i = infs; *i; i++) { 899 if (!strcasecmp(s, *i)) 900 return 1; 901 } 902 return 0; 903 } 904 905 static u_quad_t 906 multiply(u_quad_t n1, u_quad_t n2) 907 { 908 static int bpw = 0; 909 u_quad_t m; 910 u_quad_t r; 911 int b1, b2; 912 913 /* 914 * Get rid of the simple cases 915 */ 916 if (n1 == 0 || n2 == 0) 917 return (0); 918 if (n1 == 1) 919 return (n2); 920 if (n2 == 1) 921 return (n1); 922 923 /* 924 * sizeof() returns number of bytes needed for storage. 925 * This may be different from the actual number of useful bits. 926 */ 927 if (!bpw) { 928 bpw = sizeof(u_quad_t) * 8; 929 while (((u_quad_t)1 << (bpw-1)) == 0) 930 --bpw; 931 } 932 933 /* 934 * First check the magnitude of each number. If the sum of the 935 * magnatude is way to high, reject the number. (If this test 936 * is not done then the first multiply below may overflow.) 937 */ 938 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 939 ; 940 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 941 ; 942 if (b1 + b2 - 2 > bpw) { 943 errno = ERANGE; 944 return (UQUAD_MAX); 945 } 946 947 /* 948 * Decompose the multiplication to be: 949 * h1 = n1 & ~1 950 * h2 = n2 & ~1 951 * l1 = n1 & 1 952 * l2 = n2 & 1 953 * (h1 + l1) * (h2 + l2) 954 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 955 * 956 * Since h1 && h2 do not have the low bit set, we can then say: 957 * 958 * (h1>>1 * h2>>1 * 4) + ... 959 * 960 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 961 * overflow. 962 * 963 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 964 * then adding in residual amout will cause an overflow. 965 */ 966 967 m = (n1 >> 1) * (n2 >> 1); 968 969 if (m >= ((u_quad_t)1 << (bpw-2))) { 970 errno = ERANGE; 971 return (UQUAD_MAX); 972 } 973 974 m *= 4; 975 976 r = (n1 & n2 & 1) 977 + (n2 & 1) * (n1 & ~(u_quad_t)1) 978 + (n1 & 1) * (n2 & ~(u_quad_t)1); 979 980 if ((u_quad_t)(m + r) < m) { 981 errno = ERANGE; 982 return (UQUAD_MAX); 983 } 984 m += r; 985 986 return (m); 987 } 988