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 !defined(__minix) 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 #endif /* !defined(__minix) */ 704 705 if (flags & LOGIN_SETUSER) 706 if (setuid(uid) == -1) { 707 syslog(LOG_ERR, "setuid(%d): %m", uid); 708 login_close(flc); 709 return (-1); 710 } 711 712 if (flags & LOGIN_SETENV) 713 setuserenv(lc, envset, NULL); 714 715 if (flags & LOGIN_SETPATH) 716 setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL); 717 718 login_close(flc); 719 return (0); 720 721 out: 722 if (component_name != NULL) { 723 syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp); 724 login_close(flc); 725 return (-1); 726 } else { 727 syslog(LOG_ERR, "%s: %m", per_user_tmp); 728 login_close(flc); 729 return (-1); 730 } 731 } 732 733 void 734 setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp) 735 { 736 size_t hlen, plen; 737 int cnt = 0; 738 char *path; 739 const char *cpath; 740 char *p, *q; 741 742 _DIAGASSERT(home != NULL); 743 744 hlen = strlen(home); 745 746 p = path = login_getcapstr(lc, "path", NULL, NULL); 747 if (p) { 748 while (*p) 749 if (*p++ == '~') 750 ++cnt; 751 plen = (p - path) + cnt * (hlen + 1) + 1; 752 p = path; 753 q = path = malloc(plen); 754 if (q) { 755 while (*p) { 756 p += strspn(p, " \t"); 757 if (*p == '\0') 758 break; 759 plen = strcspn(p, " \t"); 760 if (hlen == 0 && *p == '~') { 761 p += plen; 762 continue; 763 } 764 if (q != path) 765 *q++ = ':'; 766 if (*p == '~') { 767 strcpy(q, home); 768 q += hlen; 769 ++p; 770 --plen; 771 } 772 memcpy(q, p, plen); 773 p += plen; 774 q += plen; 775 } 776 *q = '\0'; 777 cpath = path; 778 } else 779 cpath = _PATH_DEFPATH; 780 } else 781 cpath = _PATH_DEFPATH; 782 if ((*senv)(envp, "PATH", cpath, 1)) 783 warn("could not set PATH"); 784 } 785 786 /* 787 * Convert an expression of the following forms 788 * 1) A number. 789 * 2) A number followed by a b (mult by 512). 790 * 3) A number followed by a k (mult by 1024). 791 * 5) A number followed by a m (mult by 1024 * 1024). 792 * 6) A number followed by a g (mult by 1024 * 1024 * 1024). 793 * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024). 794 * 8) Two or more numbers (with/without k,b,m,g, or t). 795 * separated by x (also * for backwards compatibility), specifying 796 * the product of the indicated values. 797 */ 798 static u_quad_t 799 strtosize(const char *str, char **endptr, int radix) 800 { 801 u_quad_t num, num2; 802 char *expr, *expr2; 803 804 _DIAGASSERT(str != NULL); 805 /* endptr may be NULL */ 806 807 errno = 0; 808 num = strtouq(str, &expr, radix); 809 if (errno || expr == str) { 810 if (endptr) 811 *endptr = expr; 812 return (num); 813 } 814 815 switch(*expr) { 816 case 'b': case 'B': 817 num = multiply(num, (u_quad_t)512); 818 ++expr; 819 break; 820 case 'k': case 'K': 821 num = multiply(num, (u_quad_t)1024); 822 ++expr; 823 break; 824 case 'm': case 'M': 825 num = multiply(num, (u_quad_t)1024 * 1024); 826 ++expr; 827 break; 828 case 'g': case 'G': 829 num = multiply(num, (u_quad_t)1024 * 1024 * 1024); 830 ++expr; 831 break; 832 case 't': case 'T': 833 num = multiply(num, (u_quad_t)1024 * 1024); 834 num = multiply(num, (u_quad_t)1024 * 1024); 835 ++expr; 836 break; 837 } 838 839 if (errno) 840 goto erange; 841 842 switch(*expr) { 843 case '*': /* Backward compatible. */ 844 case 'x': 845 num2 = strtosize(expr+1, &expr2, radix); 846 if (errno) { 847 expr = expr2; 848 goto erange; 849 } 850 851 if (expr2 == expr + 1) { 852 if (endptr) 853 *endptr = expr; 854 return (num); 855 } 856 expr = expr2; 857 num = multiply(num, num2); 858 if (errno) 859 goto erange; 860 break; 861 } 862 if (endptr) 863 *endptr = expr; 864 return (num); 865 erange: 866 if (endptr) 867 *endptr = expr; 868 errno = ERANGE; 869 return (UQUAD_MAX); 870 } 871 872 static u_quad_t 873 strtolimit(const char *str, char **endptr, int radix) 874 { 875 876 _DIAGASSERT(str != NULL); 877 /* endptr may be NULL */ 878 879 if (isinfinite(str)) { 880 if (endptr) 881 *endptr = (char *)__UNCONST(str) + strlen(str); 882 return ((u_quad_t)RLIM_INFINITY); 883 } 884 return (strtosize(str, endptr, radix)); 885 } 886 887 static int 888 isinfinite(const char *s) 889 { 890 static const char *infs[] = { 891 "infinity", 892 "inf", 893 "unlimited", 894 "unlimit", 895 NULL 896 }; 897 const char **i; 898 899 _DIAGASSERT(s != NULL); 900 901 for (i = infs; *i; i++) { 902 if (!strcasecmp(s, *i)) 903 return 1; 904 } 905 return 0; 906 } 907 908 static u_quad_t 909 multiply(u_quad_t n1, u_quad_t n2) 910 { 911 static int bpw = 0; 912 u_quad_t m; 913 u_quad_t r; 914 int b1, b2; 915 916 /* 917 * Get rid of the simple cases 918 */ 919 if (n1 == 0 || n2 == 0) 920 return (0); 921 if (n1 == 1) 922 return (n2); 923 if (n2 == 1) 924 return (n1); 925 926 /* 927 * sizeof() returns number of bytes needed for storage. 928 * This may be different from the actual number of useful bits. 929 */ 930 if (!bpw) { 931 bpw = sizeof(u_quad_t) * 8; 932 while (((u_quad_t)1 << (bpw-1)) == 0) 933 --bpw; 934 } 935 936 /* 937 * First check the magnitude of each number. If the sum of the 938 * magnatude is way to high, reject the number. (If this test 939 * is not done then the first multiply below may overflow.) 940 */ 941 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 942 ; 943 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 944 ; 945 if (b1 + b2 - 2 > bpw) { 946 errno = ERANGE; 947 return (UQUAD_MAX); 948 } 949 950 /* 951 * Decompose the multiplication to be: 952 * h1 = n1 & ~1 953 * h2 = n2 & ~1 954 * l1 = n1 & 1 955 * l2 = n2 & 1 956 * (h1 + l1) * (h2 + l2) 957 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 958 * 959 * Since h1 && h2 do not have the low bit set, we can then say: 960 * 961 * (h1>>1 * h2>>1 * 4) + ... 962 * 963 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 964 * overflow. 965 * 966 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 967 * then adding in residual amout will cause an overflow. 968 */ 969 970 m = (n1 >> 1) * (n2 >> 1); 971 972 if (m >= ((u_quad_t)1 << (bpw-2))) { 973 errno = ERANGE; 974 return (UQUAD_MAX); 975 } 976 977 m *= 4; 978 979 r = (n1 & n2 & 1) 980 + (n2 & 1) * (n1 & ~(u_quad_t)1) 981 + (n1 & 1) * (n2 & ~(u_quad_t)1); 982 983 if ((u_quad_t)(m + r) < m) { 984 errno = ERANGE; 985 return (UQUAD_MAX); 986 } 987 m += r; 988 989 return (m); 990 } 991