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