1 /* $NetBSD: login_cap.c,v 1.23 2005/12/20 21:32:20 christos 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.23 2005/12/20 21:32:20 christos 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 47 #include <assert.h> 48 #include <ctype.h> 49 #include <err.h> 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <limits.h> 53 #include <login_cap.h> 54 #include <paths.h> 55 #include <pwd.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <syslog.h> 60 #include <unistd.h> 61 #include <util.h> 62 63 static u_quad_t multiply(u_quad_t, u_quad_t); 64 static u_quad_t strtolimit(const char *, char **, int); 65 static u_quad_t strtosize(const char *, char **, int); 66 static int gsetrl(login_cap_t *, int, const char *, int type); 67 static int isinfinite(const char *); 68 static int envset(void *, const char *, const char *, int); 69 70 login_cap_t * 71 login_getclass(const char *class) 72 { 73 const char *classfiles[2]; 74 login_cap_t *lc; 75 int res; 76 77 /* class may be NULL */ 78 79 if (secure_path(_PATH_LOGIN_CONF) == 0) { 80 classfiles[0] = _PATH_LOGIN_CONF; 81 classfiles[1] = NULL; 82 } else { 83 classfiles[0] = NULL; 84 } 85 86 if ((lc = malloc(sizeof(login_cap_t))) == NULL) { 87 syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__); 88 return (0); 89 } 90 91 lc->lc_cap = 0; 92 lc->lc_style = 0; 93 94 if (class == NULL || class[0] == '\0') 95 class = LOGIN_DEFCLASS; 96 97 if ((lc->lc_class = strdup(class)) == NULL) { 98 syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__); 99 free(lc); 100 return (0); 101 } 102 103 /* 104 * Not having a login.conf file is not an error condition. 105 * The individual routines deal reasonably with missing 106 * capabilities and use default values. 107 */ 108 if (classfiles[0] == NULL) 109 return(lc); 110 111 if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0) { 112 lc->lc_cap = 0; 113 switch (res) { 114 case 1: 115 syslog(LOG_ERR, "%s: couldn't resolve 'tc'", 116 lc->lc_class); 117 break; 118 case -1: 119 if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == 0) 120 return (lc); 121 syslog(LOG_ERR, "%s: unknown class", lc->lc_class); 122 break; 123 case -2: 124 syslog(LOG_ERR, "%s: getting class information: %m", 125 lc->lc_class); 126 break; 127 case -3: 128 syslog(LOG_ERR, "%s: 'tc' reference loop", 129 lc->lc_class); 130 break; 131 default: 132 syslog(LOG_ERR, "%s: unexpected cgetent error", 133 lc->lc_class); 134 break; 135 } 136 free(lc->lc_class); 137 free(lc); 138 return (0); 139 } 140 return (lc); 141 } 142 143 login_cap_t * 144 login_getpwclass(const struct passwd *pwd) 145 { 146 147 /* pwd may be NULL */ 148 149 return login_getclass(pwd ? pwd->pw_class : NULL); 150 } 151 152 char * 153 login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *e) 154 { 155 char *res = NULL; 156 int status; 157 158 errno = 0; 159 160 _DIAGASSERT(cap != NULL); 161 162 if (!lc || !lc->lc_cap) 163 return (def); 164 165 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 166 case -1: 167 if (res) 168 free(res); 169 return (def); 170 case -2: 171 syslog(LOG_ERR, "%s: getting capability %s: %m", 172 lc->lc_class, cap); 173 if (res) 174 free(res); 175 return (e); 176 default: 177 if (status >= 0) 178 return (res); 179 syslog(LOG_ERR, "%s: unexpected error with capability %s", 180 lc->lc_class, cap); 181 if (res) 182 free(res); 183 return (e); 184 } 185 } 186 187 quad_t 188 login_getcaptime(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 189 { 190 char *ep; 191 char *res = NULL, *sres; 192 int status; 193 quad_t q, r; 194 195 _DIAGASSERT(cap != NULL); 196 197 errno = 0; 198 if (!lc || !lc->lc_cap) 199 return (def); 200 201 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 202 case -1: 203 if (res) 204 free(res); 205 return (def); 206 case -2: 207 syslog(LOG_ERR, "%s: getting capability %s: %m", 208 lc->lc_class, cap); 209 errno = ERANGE; 210 if (res) 211 free(res); 212 return (e); 213 default: 214 if (status >= 0) 215 break; 216 syslog(LOG_ERR, "%s: unexpected error with capability %s", 217 lc->lc_class, cap); 218 errno = ERANGE; 219 if (res) 220 free(res); 221 return (e); 222 } 223 224 if (isinfinite(res)) 225 return (RLIM_INFINITY); 226 227 errno = 0; 228 229 q = 0; 230 sres = res; 231 while (*res) { 232 r = strtoq(res, &ep, 0); 233 if (!ep || ep == res || 234 ((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) { 235 invalid: 236 syslog(LOG_ERR, "%s:%s=%s: invalid time", 237 lc->lc_class, cap, sres); 238 errno = ERANGE; 239 free(sres); 240 return (e); 241 } 242 switch (*ep++) { 243 case '\0': 244 --ep; 245 break; 246 case 's': case 'S': 247 break; 248 case 'm': case 'M': 249 r *= 60; 250 break; 251 case 'h': case 'H': 252 r *= 60 * 60; 253 break; 254 case 'd': case 'D': 255 r *= 60 * 60 * 24; 256 break; 257 case 'w': case 'W': 258 r *= 60 * 60 * 24 * 7; 259 break; 260 case 'y': case 'Y': /* Pretty absurd */ 261 r *= 60 * 60 * 24 * 365; 262 break; 263 default: 264 goto invalid; 265 } 266 res = ep; 267 q += r; 268 } 269 free(sres); 270 return (q); 271 } 272 273 quad_t 274 login_getcapnum(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 275 { 276 char *ep; 277 char *res = NULL; 278 int status; 279 quad_t q; 280 281 _DIAGASSERT(cap != NULL); 282 283 errno = 0; 284 if (!lc || !lc->lc_cap) 285 return (def); 286 287 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 288 case -1: 289 if (res) 290 free(res); 291 return (def); 292 case -2: 293 syslog(LOG_ERR, "%s: getting capability %s: %m", 294 lc->lc_class, cap); 295 errno = ERANGE; 296 if (res) 297 free(res); 298 return (e); 299 default: 300 if (status >= 0) 301 break; 302 syslog(LOG_ERR, "%s: unexpected error with capability %s", 303 lc->lc_class, cap); 304 errno = ERANGE; 305 if (res) 306 free(res); 307 return (e); 308 } 309 310 if (isinfinite(res)) 311 return (RLIM_INFINITY); 312 313 errno = 0; 314 q = strtoq(res, &ep, 0); 315 if (!ep || ep == res || ep[0] || 316 ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 317 syslog(LOG_ERR, "%s:%s=%s: invalid number", 318 lc->lc_class, cap, res); 319 errno = ERANGE; 320 free(res); 321 return (e); 322 } 323 free(res); 324 return (q); 325 } 326 327 quad_t 328 login_getcapsize(login_cap_t *lc, const char *cap, quad_t def, quad_t e) 329 { 330 char *ep; 331 char *res = NULL; 332 int status; 333 quad_t q; 334 335 _DIAGASSERT(cap != NULL); 336 337 errno = 0; 338 339 if (!lc || !lc->lc_cap) 340 return (def); 341 342 switch (status = cgetstr(lc->lc_cap, cap, &res)) { 343 case -1: 344 if (res) 345 free(res); 346 return (def); 347 case -2: 348 syslog(LOG_ERR, "%s: getting capability %s: %m", 349 lc->lc_class, cap); 350 errno = ERANGE; 351 if (res) 352 free(res); 353 return (e); 354 default: 355 if (status >= 0) 356 break; 357 syslog(LOG_ERR, "%s: unexpected error with capability %s", 358 lc->lc_class, cap); 359 errno = ERANGE; 360 if (res) 361 free(res); 362 return (e); 363 } 364 365 errno = 0; 366 q = strtolimit(res, &ep, 0); 367 if (!ep || ep == res || (ep[0] && ep[1]) || 368 ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) { 369 syslog(LOG_ERR, "%s:%s=%s: invalid size", 370 lc->lc_class, cap, res); 371 errno = ERANGE; 372 free(res); 373 return (e); 374 } 375 free(res); 376 return (q); 377 } 378 379 int 380 login_getcapbool(login_cap_t *lc, const char *cap, u_int def) 381 { 382 383 _DIAGASSERT(cap != NULL); 384 385 if (!lc || !lc->lc_cap) 386 return (def); 387 388 return (cgetcap(lc->lc_cap, cap, ':') != NULL); 389 } 390 391 void 392 login_close(login_cap_t *lc) 393 { 394 395 if (lc) { 396 if (lc->lc_class) 397 free(lc->lc_class); 398 if (lc->lc_cap) 399 free(lc->lc_cap); 400 if (lc->lc_style) 401 free(lc->lc_style); 402 free(lc); 403 } 404 } 405 406 #define R_CTIME 1 407 #define R_CSIZE 2 408 #define R_CNUMB 3 409 410 static struct { 411 int what; 412 int type; 413 const char *name; 414 } r_list[] = { 415 { RLIMIT_CPU, R_CTIME, "cputime", }, 416 { RLIMIT_FSIZE, R_CSIZE, "filesize", }, 417 { RLIMIT_DATA, R_CSIZE, "datasize", }, 418 { RLIMIT_STACK, R_CSIZE, "stacksize", }, 419 { RLIMIT_RSS, R_CSIZE, "memoryuse", }, 420 { RLIMIT_MEMLOCK, R_CSIZE, "memorylocked", }, 421 { RLIMIT_NPROC, R_CNUMB, "maxproc", }, 422 { RLIMIT_NOFILE, R_CNUMB, "openfiles", }, 423 { RLIMIT_CORE, R_CSIZE, "coredumpsize", }, 424 { RLIMIT_SBSIZE, R_CSIZE, "sbsize", }, 425 { -1, 0, 0 } 426 }; 427 428 static int 429 gsetrl(login_cap_t *lc, int what, const char *name, int type) 430 { 431 struct rlimit rl; 432 struct rlimit r; 433 char name_cur[32]; 434 char name_max[32]; 435 436 _DIAGASSERT(name != NULL); 437 438 sprintf(name_cur, "%s-cur", name); 439 sprintf(name_max, "%s-max", name); 440 441 if (getrlimit(what, &r)) { 442 syslog(LOG_ERR, "getting resource limit: %m"); 443 return (-1); 444 } 445 446 #define RCUR r.rlim_cur 447 #define RMAX r.rlim_max 448 449 switch (type) { 450 case R_CTIME: 451 RCUR = login_getcaptime(lc, name, RCUR, RCUR); 452 RMAX = login_getcaptime(lc, name, RMAX, RMAX); 453 rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR); 454 rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX); 455 break; 456 case R_CSIZE: 457 RCUR = login_getcapsize(lc, name, RCUR, RCUR); 458 RMAX = login_getcapsize(lc, name, RMAX, RMAX); 459 rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR); 460 rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX); 461 break; 462 case R_CNUMB: 463 RCUR = login_getcapnum(lc, name, RCUR, RCUR); 464 RMAX = login_getcapnum(lc, name, RMAX, RMAX); 465 rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR); 466 rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX); 467 break; 468 default: 469 return (-1); 470 } 471 472 if (setrlimit(what, &rl)) { 473 syslog(LOG_ERR, "%s: setting resource limit %s: %m", 474 lc->lc_class, name); 475 return (-1); 476 } 477 #undef RCUR 478 #undef RMAX 479 return (0); 480 } 481 482 static int 483 /*ARGSUSED*/ 484 envset(void *envp, const char *name, const char *value, int overwrite) 485 { 486 return setenv(name, value, overwrite); 487 } 488 489 int 490 setuserenv(login_cap_t *lc, envfunc_t senv, void *envp) 491 { 492 const char *stop = ", \t"; 493 int i, count; 494 char *ptr; 495 char **res; 496 char *str = login_getcapstr(lc, "setenv", NULL, NULL); 497 498 if (str == NULL || *str == '\0') 499 return 0; 500 501 /* count the sub-strings */ 502 for (i = 1, ptr = str; *ptr; i++) { 503 ptr += strcspn(ptr, stop); 504 if (*ptr) 505 ptr++; 506 } 507 508 /* allocate ptr array and string */ 509 count = i; 510 res = malloc(count * sizeof(char *) + strlen(str) + 1); 511 512 if (!res) 513 return -1; 514 515 ptr = (char *)(void *)res + count * sizeof(char *); 516 strcpy(ptr, str); 517 518 /* split string */ 519 for (i = 0; *ptr && i < count; i++) { 520 res[i] = ptr; 521 ptr += strcspn(ptr, stop); 522 if (*ptr) 523 *ptr++ = '\0'; 524 } 525 526 res[i] = NULL; 527 528 for (i = 0; i < count && res[i]; i++) { 529 if (*res[i] != '\0') { 530 if ((ptr = strchr(res[i], '=')) != NULL) 531 *ptr++ = '\0'; 532 else 533 ptr = NULL; 534 (void)(*senv)(envp, res[i], ptr ? ptr : "", 1); 535 } 536 } 537 538 free(res); 539 return 0; 540 } 541 542 int 543 setclasscontext(const char *class, u_int flags) 544 { 545 int ret; 546 login_cap_t *lc; 547 548 flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK | 549 LOGIN_SETPATH; 550 551 lc = login_getclass(class); 552 ret = lc ? setusercontext(lc, NULL, 0, flags) : -1; 553 login_close(lc); 554 return (ret); 555 } 556 557 int 558 setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) 559 { 560 login_cap_t *flc; 561 quad_t p; 562 int i; 563 564 flc = NULL; 565 566 if (!lc) 567 flc = lc = login_getclass(pwd ? pwd->pw_class : NULL); 568 569 /* 570 * Without the pwd entry being passed we cannot set either 571 * the group or the login. We could complain about it. 572 */ 573 if (pwd == NULL) 574 flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN); 575 576 if (flags & LOGIN_SETRESOURCES) 577 for (i = 0; r_list[i].name; ++i) 578 if (gsetrl(lc, r_list[i].what, r_list[i].name, 579 r_list[i].type)) 580 /* XXX - call syslog()? */; 581 582 if (flags & LOGIN_SETPRIORITY) { 583 p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0); 584 585 if (setpriority(PRIO_PROCESS, 0, (int)p) < 0) 586 syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class); 587 } 588 589 if (flags & LOGIN_SETUMASK) { 590 p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK, 591 (quad_t) LOGIN_DEFUMASK); 592 umask((mode_t)p); 593 } 594 595 if (flags & LOGIN_SETGROUP) { 596 if (setgid(pwd->pw_gid) < 0) { 597 syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid); 598 login_close(flc); 599 return (-1); 600 } 601 602 if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) { 603 syslog(LOG_ERR, "initgroups(%s,%d): %m", 604 pwd->pw_name, pwd->pw_gid); 605 login_close(flc); 606 return (-1); 607 } 608 } 609 610 if (flags & LOGIN_SETLOGIN) 611 if (setlogin(pwd->pw_name) < 0) { 612 syslog(LOG_ERR, "setlogin(%s) failure: %m", 613 pwd->pw_name); 614 login_close(flc); 615 return (-1); 616 } 617 618 if (flags & LOGIN_SETUSER) 619 if (setuid(uid) < 0) { 620 syslog(LOG_ERR, "setuid(%d): %m", uid); 621 login_close(flc); 622 return (-1); 623 } 624 625 if (flags & LOGIN_SETENV) 626 setuserenv(lc, envset, NULL); 627 628 if (flags & LOGIN_SETPATH) 629 setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL); 630 631 login_close(flc); 632 return (0); 633 } 634 635 void 636 setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp) 637 { 638 size_t hlen, plen; 639 int cnt = 0; 640 char *path; 641 const char *cpath; 642 char *p, *q; 643 644 _DIAGASSERT(home != NULL); 645 646 hlen = strlen(home); 647 648 p = path = login_getcapstr(lc, "path", NULL, NULL); 649 if (p) { 650 while (*p) 651 if (*p++ == '~') 652 ++cnt; 653 plen = (p - path) + cnt * (hlen + 1) + 1; 654 p = path; 655 q = path = malloc(plen); 656 if (q) { 657 while (*p) { 658 p += strspn(p, " \t"); 659 if (*p == '\0') 660 break; 661 plen = strcspn(p, " \t"); 662 if (hlen == 0 && *p == '~') { 663 p += plen; 664 continue; 665 } 666 if (q != path) 667 *q++ = ':'; 668 if (*p == '~') { 669 strcpy(q, home); 670 q += hlen; 671 ++p; 672 --plen; 673 } 674 memcpy(q, p, plen); 675 p += plen; 676 q += plen; 677 } 678 *q = '\0'; 679 cpath = path; 680 } else 681 cpath = _PATH_DEFPATH; 682 } else 683 cpath = _PATH_DEFPATH; 684 if ((*senv)(envp, "PATH", cpath, 1)) 685 warn("could not set PATH"); 686 } 687 688 /* 689 * Convert an expression of the following forms 690 * 1) A number. 691 * 2) A number followed by a b (mult by 512). 692 * 3) A number followed by a k (mult by 1024). 693 * 5) A number followed by a m (mult by 1024 * 1024). 694 * 6) A number followed by a g (mult by 1024 * 1024 * 1024). 695 * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024). 696 * 8) Two or more numbers (with/without k,b,m,g, or t). 697 * separated by x (also * for backwards compatibility), specifying 698 * the product of the indicated values. 699 */ 700 static u_quad_t 701 strtosize(const char *str, char **endptr, int radix) 702 { 703 u_quad_t num, num2; 704 char *expr, *expr2; 705 706 _DIAGASSERT(str != NULL); 707 /* endptr may be NULL */ 708 709 errno = 0; 710 num = strtouq(str, &expr, radix); 711 if (errno || expr == str) { 712 if (endptr) 713 *endptr = expr; 714 return (num); 715 } 716 717 switch(*expr) { 718 case 'b': case 'B': 719 num = multiply(num, (u_quad_t)512); 720 ++expr; 721 break; 722 case 'k': case 'K': 723 num = multiply(num, (u_quad_t)1024); 724 ++expr; 725 break; 726 case 'm': case 'M': 727 num = multiply(num, (u_quad_t)1024 * 1024); 728 ++expr; 729 break; 730 case 'g': case 'G': 731 num = multiply(num, (u_quad_t)1024 * 1024 * 1024); 732 ++expr; 733 break; 734 case 't': case 'T': 735 num = multiply(num, (u_quad_t)1024 * 1024); 736 num = multiply(num, (u_quad_t)1024 * 1024); 737 ++expr; 738 break; 739 } 740 741 if (errno) 742 goto erange; 743 744 switch(*expr) { 745 case '*': /* Backward compatible. */ 746 case 'x': 747 num2 = strtosize(expr+1, &expr2, radix); 748 if (errno) { 749 expr = expr2; 750 goto erange; 751 } 752 753 if (expr2 == expr + 1) { 754 if (endptr) 755 *endptr = expr; 756 return (num); 757 } 758 expr = expr2; 759 num = multiply(num, num2); 760 if (errno) 761 goto erange; 762 break; 763 } 764 if (endptr) 765 *endptr = expr; 766 return (num); 767 erange: 768 if (endptr) 769 *endptr = expr; 770 errno = ERANGE; 771 return (UQUAD_MAX); 772 } 773 774 static u_quad_t 775 strtolimit(const char *str, char **endptr, int radix) 776 { 777 778 _DIAGASSERT(str != NULL); 779 /* endptr may be NULL */ 780 781 if (isinfinite(str)) { 782 if (endptr) 783 *endptr = (char *)__UNCONST(str) + strlen(str); 784 return ((u_quad_t)RLIM_INFINITY); 785 } 786 return (strtosize(str, endptr, radix)); 787 } 788 789 static int 790 isinfinite(const char *s) 791 { 792 static const char *infs[] = { 793 "infinity", 794 "inf", 795 "unlimited", 796 "unlimit", 797 NULL 798 }; 799 const char **i; 800 801 _DIAGASSERT(s != NULL); 802 803 for (i = infs; *i; i++) { 804 if (!strcasecmp(s, *i)) 805 return 1; 806 } 807 return 0; 808 } 809 810 static u_quad_t 811 multiply(u_quad_t n1, u_quad_t n2) 812 { 813 static int bpw = 0; 814 u_quad_t m; 815 u_quad_t r; 816 int b1, b2; 817 818 /* 819 * Get rid of the simple cases 820 */ 821 if (n1 == 0 || n2 == 0) 822 return (0); 823 if (n1 == 1) 824 return (n2); 825 if (n2 == 1) 826 return (n1); 827 828 /* 829 * sizeof() returns number of bytes needed for storage. 830 * This may be different from the actual number of useful bits. 831 */ 832 if (!bpw) { 833 bpw = sizeof(u_quad_t) * 8; 834 while (((u_quad_t)1 << (bpw-1)) == 0) 835 --bpw; 836 } 837 838 /* 839 * First check the magnitude of each number. If the sum of the 840 * magnatude is way to high, reject the number. (If this test 841 * is not done then the first multiply below may overflow.) 842 */ 843 for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1) 844 ; 845 for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2) 846 ; 847 if (b1 + b2 - 2 > bpw) { 848 errno = ERANGE; 849 return (UQUAD_MAX); 850 } 851 852 /* 853 * Decompose the multiplication to be: 854 * h1 = n1 & ~1 855 * h2 = n2 & ~1 856 * l1 = n1 & 1 857 * l2 = n2 & 1 858 * (h1 + l1) * (h2 + l2) 859 * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2) 860 * 861 * Since h1 && h2 do not have the low bit set, we can then say: 862 * 863 * (h1>>1 * h2>>1 * 4) + ... 864 * 865 * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will 866 * overflow. 867 * 868 * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2) 869 * then adding in residual amout will cause an overflow. 870 */ 871 872 m = (n1 >> 1) * (n2 >> 1); 873 874 if (m >= ((u_quad_t)1 << (bpw-2))) { 875 errno = ERANGE; 876 return (UQUAD_MAX); 877 } 878 879 m *= 4; 880 881 r = (n1 & n2 & 1) 882 + (n2 & 1) * (n1 & ~(u_quad_t)1) 883 + (n1 & 1) * (n2 & ~(u_quad_t)1); 884 885 if ((u_quad_t)(m + r) < m) { 886 errno = ERANGE; 887 return (UQUAD_MAX); 888 } 889 m += r; 890 891 return (m); 892 } 893