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