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