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