1*0a6a1f1dSLionel Sambuc /* $NetBSD: login_cap.c,v 1.32 2015/07/11 09:21:22 kamil Exp $ */
20c3983b2SBen Gras
30c3983b2SBen Gras /*-
40c3983b2SBen Gras * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved.
50c3983b2SBen Gras *
60c3983b2SBen Gras * Redistribution and use in source and binary forms, with or without
70c3983b2SBen Gras * modification, are permitted provided that the following conditions
80c3983b2SBen Gras * are met:
90c3983b2SBen Gras * 1. Redistributions of source code must retain the above copyright
100c3983b2SBen Gras * notice, this list of conditions and the following disclaimer.
110c3983b2SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
120c3983b2SBen Gras * notice, this list of conditions and the following disclaimer in the
130c3983b2SBen Gras * documentation and/or other materials provided with the distribution.
140c3983b2SBen Gras * 3. All advertising materials mentioning features or use of this software
150c3983b2SBen Gras * must display the following acknowledgement:
160c3983b2SBen Gras * This product includes software developed by Berkeley Software Design,
170c3983b2SBen Gras * Inc.
180c3983b2SBen Gras * 4. The name of Berkeley Software Design, Inc. may not be used to endorse
190c3983b2SBen Gras * or promote products derived from this software without specific prior
200c3983b2SBen Gras * written permission.
210c3983b2SBen Gras *
220c3983b2SBen Gras * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
230c3983b2SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
240c3983b2SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
250c3983b2SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
260c3983b2SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
270c3983b2SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
280c3983b2SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
290c3983b2SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
300c3983b2SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
310c3983b2SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
320c3983b2SBen Gras * SUCH DAMAGE.
330c3983b2SBen Gras *
340c3983b2SBen Gras * BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp
350c3983b2SBen Gras */
360c3983b2SBen Gras
370c3983b2SBen Gras #include <sys/cdefs.h>
380c3983b2SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
39*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: login_cap.c,v 1.32 2015/07/11 09:21:22 kamil Exp $");
400c3983b2SBen Gras #endif /* LIBC_SCCS and not lint */
410c3983b2SBen Gras
420c3983b2SBen Gras #include <sys/types.h>
430c3983b2SBen Gras #include <sys/stat.h>
440c3983b2SBen Gras #include <sys/time.h>
450c3983b2SBen Gras #include <sys/resource.h>
460c3983b2SBen Gras #include <sys/param.h>
470c3983b2SBen Gras
480c3983b2SBen Gras #include <assert.h>
490c3983b2SBen Gras #include <ctype.h>
500c3983b2SBen Gras #include <err.h>
510c3983b2SBen Gras #include <errno.h>
520c3983b2SBen Gras #include <fcntl.h>
530c3983b2SBen Gras #include <limits.h>
540c3983b2SBen Gras #include <login_cap.h>
550c3983b2SBen Gras #include <paths.h>
560c3983b2SBen Gras #include <pwd.h>
570c3983b2SBen Gras #include <stdio.h>
580c3983b2SBen Gras #include <stdlib.h>
590c3983b2SBen Gras #include <string.h>
600c3983b2SBen Gras #include <syslog.h>
610c3983b2SBen Gras #include <unistd.h>
620c3983b2SBen Gras #include <util.h>
630c3983b2SBen Gras
640c3983b2SBen Gras static u_quad_t multiply(u_quad_t, u_quad_t);
650c3983b2SBen Gras static u_quad_t strtolimit(const char *, char **, int);
660c3983b2SBen Gras static u_quad_t strtosize(const char *, char **, int);
670c3983b2SBen Gras static int gsetrl(login_cap_t *, int, const char *, int type);
680c3983b2SBen Gras static int isinfinite(const char *);
690c3983b2SBen Gras static int envset(void *, const char *, const char *, int);
700c3983b2SBen Gras
710c3983b2SBen Gras login_cap_t *
login_getclass(const char * class)720c3983b2SBen Gras login_getclass(const char *class)
730c3983b2SBen Gras {
740c3983b2SBen Gras const char *classfiles[2];
750c3983b2SBen Gras login_cap_t *lc;
760c3983b2SBen Gras int res;
770c3983b2SBen Gras
780c3983b2SBen Gras /* class may be NULL */
790c3983b2SBen Gras
800c3983b2SBen Gras if (secure_path(_PATH_LOGIN_CONF) == 0) {
810c3983b2SBen Gras classfiles[0] = _PATH_LOGIN_CONF;
820c3983b2SBen Gras classfiles[1] = NULL;
830c3983b2SBen Gras } else {
840c3983b2SBen Gras classfiles[0] = NULL;
850c3983b2SBen Gras }
860c3983b2SBen Gras
870c3983b2SBen Gras if ((lc = malloc(sizeof(login_cap_t))) == NULL) {
880c3983b2SBen Gras syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__);
890c3983b2SBen Gras return (0);
900c3983b2SBen Gras }
910c3983b2SBen Gras
920c3983b2SBen Gras lc->lc_cap = 0;
930c3983b2SBen Gras lc->lc_style = 0;
940c3983b2SBen Gras
950c3983b2SBen Gras if (class == NULL || class[0] == '\0')
960c3983b2SBen Gras class = LOGIN_DEFCLASS;
970c3983b2SBen Gras
980c3983b2SBen Gras if ((lc->lc_class = strdup(class)) == NULL) {
990c3983b2SBen Gras syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__);
1000c3983b2SBen Gras free(lc);
1010c3983b2SBen Gras return (0);
1020c3983b2SBen Gras }
1030c3983b2SBen Gras
1040c3983b2SBen Gras /*
1050c3983b2SBen Gras * Not having a login.conf file is not an error condition.
1060c3983b2SBen Gras * The individual routines deal reasonably with missing
1070c3983b2SBen Gras * capabilities and use default values.
1080c3983b2SBen Gras */
1090c3983b2SBen Gras if (classfiles[0] == NULL)
1100c3983b2SBen Gras return(lc);
1110c3983b2SBen Gras
1120c3983b2SBen Gras if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0) {
1130c3983b2SBen Gras lc->lc_cap = 0;
1140c3983b2SBen Gras switch (res) {
1150c3983b2SBen Gras case 1:
1160c3983b2SBen Gras syslog(LOG_ERR, "%s: couldn't resolve 'tc'",
1170c3983b2SBen Gras lc->lc_class);
1180c3983b2SBen Gras break;
1190c3983b2SBen Gras case -1:
1200c3983b2SBen Gras if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == 0)
1210c3983b2SBen Gras return (lc);
1220c3983b2SBen Gras syslog(LOG_ERR, "%s: unknown class", lc->lc_class);
1230c3983b2SBen Gras break;
1240c3983b2SBen Gras case -2:
1250c3983b2SBen Gras syslog(LOG_ERR, "%s: getting class information: %m",
1260c3983b2SBen Gras lc->lc_class);
1270c3983b2SBen Gras break;
1280c3983b2SBen Gras case -3:
1290c3983b2SBen Gras syslog(LOG_ERR, "%s: 'tc' reference loop",
1300c3983b2SBen Gras lc->lc_class);
1310c3983b2SBen Gras break;
1320c3983b2SBen Gras default:
1330c3983b2SBen Gras syslog(LOG_ERR, "%s: unexpected cgetent error",
1340c3983b2SBen Gras lc->lc_class);
1350c3983b2SBen Gras break;
1360c3983b2SBen Gras }
1370c3983b2SBen Gras free(lc->lc_class);
1380c3983b2SBen Gras free(lc);
1390c3983b2SBen Gras return (0);
1400c3983b2SBen Gras }
1410c3983b2SBen Gras return (lc);
1420c3983b2SBen Gras }
1430c3983b2SBen Gras
1440c3983b2SBen Gras login_cap_t *
login_getpwclass(const struct passwd * pwd)1450c3983b2SBen Gras login_getpwclass(const struct passwd *pwd)
1460c3983b2SBen Gras {
1470c3983b2SBen Gras
1480c3983b2SBen Gras /* pwd may be NULL */
1490c3983b2SBen Gras
1500c3983b2SBen Gras return login_getclass(pwd ? pwd->pw_class : NULL);
1510c3983b2SBen Gras }
1520c3983b2SBen Gras
1530c3983b2SBen Gras char *
login_getcapstr(login_cap_t * lc,const char * cap,char * def,char * e)1540c3983b2SBen Gras login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *e)
1550c3983b2SBen Gras {
1560c3983b2SBen Gras char *res = NULL;
1570c3983b2SBen Gras int status;
1580c3983b2SBen Gras
1590c3983b2SBen Gras errno = 0;
1600c3983b2SBen Gras
1610c3983b2SBen Gras _DIAGASSERT(cap != NULL);
1620c3983b2SBen Gras
1630c3983b2SBen Gras if (!lc || !lc->lc_cap)
1640c3983b2SBen Gras return (def);
1650c3983b2SBen Gras
1660c3983b2SBen Gras switch (status = cgetstr(lc->lc_cap, cap, &res)) {
1670c3983b2SBen Gras case -1:
1680c3983b2SBen Gras if (res)
1690c3983b2SBen Gras free(res);
1700c3983b2SBen Gras return (def);
1710c3983b2SBen Gras case -2:
1720c3983b2SBen Gras syslog(LOG_ERR, "%s: getting capability %s: %m",
1730c3983b2SBen Gras lc->lc_class, cap);
1740c3983b2SBen Gras if (res)
1750c3983b2SBen Gras free(res);
1760c3983b2SBen Gras return (e);
1770c3983b2SBen Gras default:
1780c3983b2SBen Gras if (status >= 0)
1790c3983b2SBen Gras return (res);
1800c3983b2SBen Gras syslog(LOG_ERR, "%s: unexpected error with capability %s",
1810c3983b2SBen Gras lc->lc_class, cap);
1820c3983b2SBen Gras if (res)
1830c3983b2SBen Gras free(res);
1840c3983b2SBen Gras return (e);
1850c3983b2SBen Gras }
1860c3983b2SBen Gras }
1870c3983b2SBen Gras
1880c3983b2SBen Gras quad_t
login_getcaptime(login_cap_t * lc,const char * cap,quad_t def,quad_t e)1890c3983b2SBen Gras login_getcaptime(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
1900c3983b2SBen Gras {
1910c3983b2SBen Gras char *ep;
1920c3983b2SBen Gras char *res = NULL, *sres;
1930c3983b2SBen Gras int status;
1940c3983b2SBen Gras quad_t q, r;
1950c3983b2SBen Gras
1960c3983b2SBen Gras _DIAGASSERT(cap != NULL);
1970c3983b2SBen Gras
1980c3983b2SBen Gras errno = 0;
1990c3983b2SBen Gras if (!lc || !lc->lc_cap)
2000c3983b2SBen Gras return (def);
2010c3983b2SBen Gras
2020c3983b2SBen Gras switch (status = cgetstr(lc->lc_cap, cap, &res)) {
2030c3983b2SBen Gras case -1:
2040c3983b2SBen Gras if (res)
2050c3983b2SBen Gras free(res);
2060c3983b2SBen Gras return (def);
2070c3983b2SBen Gras case -2:
2080c3983b2SBen Gras syslog(LOG_ERR, "%s: getting capability %s: %m",
2090c3983b2SBen Gras lc->lc_class, cap);
2100c3983b2SBen Gras errno = ERANGE;
2110c3983b2SBen Gras if (res)
2120c3983b2SBen Gras free(res);
2130c3983b2SBen Gras return (e);
2140c3983b2SBen Gras default:
2150c3983b2SBen Gras if (status >= 0)
2160c3983b2SBen Gras break;
2170c3983b2SBen Gras syslog(LOG_ERR, "%s: unexpected error with capability %s",
2180c3983b2SBen Gras lc->lc_class, cap);
2190c3983b2SBen Gras errno = ERANGE;
2200c3983b2SBen Gras if (res)
2210c3983b2SBen Gras free(res);
2220c3983b2SBen Gras return (e);
2230c3983b2SBen Gras }
2240c3983b2SBen Gras
2250c3983b2SBen Gras if (isinfinite(res))
2260c3983b2SBen Gras return (RLIM_INFINITY);
2270c3983b2SBen Gras
2280c3983b2SBen Gras errno = 0;
2290c3983b2SBen Gras
2300c3983b2SBen Gras q = 0;
2310c3983b2SBen Gras sres = res;
2320c3983b2SBen Gras while (*res) {
2330c3983b2SBen Gras r = strtoq(res, &ep, 0);
2340c3983b2SBen Gras if (!ep || ep == res ||
2350c3983b2SBen Gras ((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) {
2360c3983b2SBen Gras invalid:
2370c3983b2SBen Gras syslog(LOG_ERR, "%s:%s=%s: invalid time",
2380c3983b2SBen Gras lc->lc_class, cap, sres);
2390c3983b2SBen Gras errno = ERANGE;
2400c3983b2SBen Gras free(sres);
2410c3983b2SBen Gras return (e);
2420c3983b2SBen Gras }
2430c3983b2SBen Gras switch (*ep++) {
2440c3983b2SBen Gras case '\0':
2450c3983b2SBen Gras --ep;
2460c3983b2SBen Gras break;
2470c3983b2SBen Gras case 's': case 'S':
2480c3983b2SBen Gras break;
2490c3983b2SBen Gras case 'm': case 'M':
2500c3983b2SBen Gras r *= 60;
2510c3983b2SBen Gras break;
2520c3983b2SBen Gras case 'h': case 'H':
2530c3983b2SBen Gras r *= 60 * 60;
2540c3983b2SBen Gras break;
2550c3983b2SBen Gras case 'd': case 'D':
2560c3983b2SBen Gras r *= 60 * 60 * 24;
2570c3983b2SBen Gras break;
2580c3983b2SBen Gras case 'w': case 'W':
2590c3983b2SBen Gras r *= 60 * 60 * 24 * 7;
2600c3983b2SBen Gras break;
2610c3983b2SBen Gras case 'y': case 'Y': /* Pretty absurd */
2620c3983b2SBen Gras r *= 60 * 60 * 24 * 365;
2630c3983b2SBen Gras break;
2640c3983b2SBen Gras default:
2650c3983b2SBen Gras goto invalid;
2660c3983b2SBen Gras }
2670c3983b2SBen Gras res = ep;
2680c3983b2SBen Gras q += r;
2690c3983b2SBen Gras }
2700c3983b2SBen Gras free(sres);
2710c3983b2SBen Gras return (q);
2720c3983b2SBen Gras }
2730c3983b2SBen Gras
2740c3983b2SBen Gras quad_t
login_getcapnum(login_cap_t * lc,const char * cap,quad_t def,quad_t e)2750c3983b2SBen Gras login_getcapnum(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
2760c3983b2SBen Gras {
2770c3983b2SBen Gras char *ep;
2780c3983b2SBen Gras char *res = NULL;
2790c3983b2SBen Gras int status;
2800c3983b2SBen Gras quad_t q;
2810c3983b2SBen Gras
2820c3983b2SBen Gras _DIAGASSERT(cap != NULL);
2830c3983b2SBen Gras
2840c3983b2SBen Gras errno = 0;
2850c3983b2SBen Gras if (!lc || !lc->lc_cap)
2860c3983b2SBen Gras return (def);
2870c3983b2SBen Gras
2880c3983b2SBen Gras switch (status = cgetstr(lc->lc_cap, cap, &res)) {
2890c3983b2SBen Gras case -1:
2900c3983b2SBen Gras if (res)
2910c3983b2SBen Gras free(res);
2920c3983b2SBen Gras return (def);
2930c3983b2SBen Gras case -2:
2940c3983b2SBen Gras syslog(LOG_ERR, "%s: getting capability %s: %m",
2950c3983b2SBen Gras lc->lc_class, cap);
2960c3983b2SBen Gras errno = ERANGE;
2970c3983b2SBen Gras if (res)
2980c3983b2SBen Gras free(res);
2990c3983b2SBen Gras return (e);
3000c3983b2SBen Gras default:
3010c3983b2SBen Gras if (status >= 0)
3020c3983b2SBen Gras break;
3030c3983b2SBen Gras syslog(LOG_ERR, "%s: unexpected error with capability %s",
3040c3983b2SBen Gras lc->lc_class, cap);
3050c3983b2SBen Gras errno = ERANGE;
3060c3983b2SBen Gras if (res)
3070c3983b2SBen Gras free(res);
3080c3983b2SBen Gras return (e);
3090c3983b2SBen Gras }
3100c3983b2SBen Gras
3110c3983b2SBen Gras if (isinfinite(res))
3120c3983b2SBen Gras return (RLIM_INFINITY);
3130c3983b2SBen Gras
3140c3983b2SBen Gras errno = 0;
3150c3983b2SBen Gras q = strtoq(res, &ep, 0);
3160c3983b2SBen Gras if (!ep || ep == res || ep[0] ||
3170c3983b2SBen Gras ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
3180c3983b2SBen Gras syslog(LOG_ERR, "%s:%s=%s: invalid number",
3190c3983b2SBen Gras lc->lc_class, cap, res);
3200c3983b2SBen Gras errno = ERANGE;
3210c3983b2SBen Gras free(res);
3220c3983b2SBen Gras return (e);
3230c3983b2SBen Gras }
3240c3983b2SBen Gras free(res);
3250c3983b2SBen Gras return (q);
3260c3983b2SBen Gras }
3270c3983b2SBen Gras
3280c3983b2SBen Gras quad_t
login_getcapsize(login_cap_t * lc,const char * cap,quad_t def,quad_t e)3290c3983b2SBen Gras login_getcapsize(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
3300c3983b2SBen Gras {
3310c3983b2SBen Gras char *ep;
3320c3983b2SBen Gras char *res = NULL;
3330c3983b2SBen Gras int status;
3340c3983b2SBen Gras quad_t q;
3350c3983b2SBen Gras
3360c3983b2SBen Gras _DIAGASSERT(cap != NULL);
3370c3983b2SBen Gras
3380c3983b2SBen Gras errno = 0;
3390c3983b2SBen Gras
3400c3983b2SBen Gras if (!lc || !lc->lc_cap)
3410c3983b2SBen Gras return (def);
3420c3983b2SBen Gras
3430c3983b2SBen Gras switch (status = cgetstr(lc->lc_cap, cap, &res)) {
3440c3983b2SBen Gras case -1:
3450c3983b2SBen Gras if (res)
3460c3983b2SBen Gras free(res);
3470c3983b2SBen Gras return (def);
3480c3983b2SBen Gras case -2:
3490c3983b2SBen Gras syslog(LOG_ERR, "%s: getting capability %s: %m",
3500c3983b2SBen Gras lc->lc_class, cap);
3510c3983b2SBen Gras errno = ERANGE;
3520c3983b2SBen Gras if (res)
3530c3983b2SBen Gras free(res);
3540c3983b2SBen Gras return (e);
3550c3983b2SBen Gras default:
3560c3983b2SBen Gras if (status >= 0)
3570c3983b2SBen Gras break;
3580c3983b2SBen Gras syslog(LOG_ERR, "%s: unexpected error with capability %s",
3590c3983b2SBen Gras lc->lc_class, cap);
3600c3983b2SBen Gras errno = ERANGE;
3610c3983b2SBen Gras if (res)
3620c3983b2SBen Gras free(res);
3630c3983b2SBen Gras return (e);
3640c3983b2SBen Gras }
3650c3983b2SBen Gras
3660c3983b2SBen Gras errno = 0;
3670c3983b2SBen Gras q = strtolimit(res, &ep, 0);
3680c3983b2SBen Gras if (!ep || ep == res || (ep[0] && ep[1]) ||
3690c3983b2SBen Gras ((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
3700c3983b2SBen Gras syslog(LOG_ERR, "%s:%s=%s: invalid size",
3710c3983b2SBen Gras lc->lc_class, cap, res);
3720c3983b2SBen Gras errno = ERANGE;
3730c3983b2SBen Gras free(res);
3740c3983b2SBen Gras return (e);
3750c3983b2SBen Gras }
3760c3983b2SBen Gras free(res);
3770c3983b2SBen Gras return (q);
3780c3983b2SBen Gras }
3790c3983b2SBen Gras
3800c3983b2SBen Gras int
login_getcapbool(login_cap_t * lc,const char * cap,u_int def)3810c3983b2SBen Gras login_getcapbool(login_cap_t *lc, const char *cap, u_int def)
3820c3983b2SBen Gras {
3830c3983b2SBen Gras
3840c3983b2SBen Gras _DIAGASSERT(cap != NULL);
3850c3983b2SBen Gras
3860c3983b2SBen Gras if (!lc || !lc->lc_cap)
3870c3983b2SBen Gras return (def);
3880c3983b2SBen Gras
3890c3983b2SBen Gras return (cgetcap(lc->lc_cap, cap, ':') != NULL);
3900c3983b2SBen Gras }
3910c3983b2SBen Gras
3920c3983b2SBen Gras void
login_close(login_cap_t * lc)3930c3983b2SBen Gras login_close(login_cap_t *lc)
3940c3983b2SBen Gras {
3950c3983b2SBen Gras
3960c3983b2SBen Gras if (lc) {
3970c3983b2SBen Gras if (lc->lc_class)
3980c3983b2SBen Gras free(lc->lc_class);
3990c3983b2SBen Gras if (lc->lc_cap)
4000c3983b2SBen Gras free(lc->lc_cap);
4010c3983b2SBen Gras if (lc->lc_style)
4020c3983b2SBen Gras free(lc->lc_style);
4030c3983b2SBen Gras free(lc);
4040c3983b2SBen Gras }
4050c3983b2SBen Gras }
4060c3983b2SBen Gras
4070c3983b2SBen Gras #define R_CTIME 1
4080c3983b2SBen Gras #define R_CSIZE 2
4090c3983b2SBen Gras #define R_CNUMB 3
4100c3983b2SBen Gras
4110c3983b2SBen Gras static struct {
4120c3983b2SBen Gras int what;
4130c3983b2SBen Gras int type;
4140c3983b2SBen Gras const char *name;
4150c3983b2SBen Gras } r_list[] = {
4160c3983b2SBen Gras { RLIMIT_CPU, R_CTIME, "cputime", },
4170c3983b2SBen Gras { RLIMIT_FSIZE, R_CSIZE, "filesize", },
4180c3983b2SBen Gras { RLIMIT_DATA, R_CSIZE, "datasize", },
4190c3983b2SBen Gras { RLIMIT_STACK, R_CSIZE, "stacksize", },
4200c3983b2SBen Gras { RLIMIT_RSS, R_CSIZE, "memoryuse", },
4210c3983b2SBen Gras { RLIMIT_MEMLOCK, R_CSIZE, "memorylocked", },
4220c3983b2SBen Gras { RLIMIT_NPROC, R_CNUMB, "maxproc", },
42384d9c625SLionel Sambuc { RLIMIT_NTHR, R_CNUMB, "maxthread", },
4240c3983b2SBen Gras { RLIMIT_NOFILE, R_CNUMB, "openfiles", },
4250c3983b2SBen Gras { RLIMIT_CORE, R_CSIZE, "coredumpsize", },
4260c3983b2SBen Gras { RLIMIT_SBSIZE, R_CSIZE, "sbsize", },
427*0a6a1f1dSLionel Sambuc { RLIMIT_AS, R_CSIZE, "vmemoryuse", },
4280c3983b2SBen Gras { -1, 0, 0 }
4290c3983b2SBen Gras };
4300c3983b2SBen Gras
4310c3983b2SBen Gras static int
gsetrl(login_cap_t * lc,int what,const char * name,int type)4320c3983b2SBen Gras gsetrl(login_cap_t *lc, int what, const char *name, int type)
4330c3983b2SBen Gras {
4340c3983b2SBen Gras struct rlimit rl;
4350c3983b2SBen Gras struct rlimit r;
4360c3983b2SBen Gras char name_cur[32];
4370c3983b2SBen Gras char name_max[32];
4380c3983b2SBen Gras
4390c3983b2SBen Gras _DIAGASSERT(name != NULL);
4400c3983b2SBen Gras
4410c3983b2SBen Gras (void)snprintf(name_cur, sizeof(name_cur), "%s-cur", name);
4420c3983b2SBen Gras (void)snprintf(name_max, sizeof(name_max), "%s-max", name);
4430c3983b2SBen Gras
4440c3983b2SBen Gras if (getrlimit(what, &r)) {
4450c3983b2SBen Gras syslog(LOG_ERR, "getting resource limit: %m");
4460c3983b2SBen Gras return (-1);
4470c3983b2SBen Gras }
4480c3983b2SBen Gras
449dba3562dSLionel Sambuc #define RCUR ((quad_t)r.rlim_cur)
450dba3562dSLionel Sambuc #define RMAX ((quad_t)r.rlim_max)
4510c3983b2SBen Gras
4520c3983b2SBen Gras switch (type) {
4530c3983b2SBen Gras case R_CTIME:
454dba3562dSLionel Sambuc r.rlim_cur = login_getcaptime(lc, name, RCUR, RCUR);
455dba3562dSLionel Sambuc r.rlim_max = login_getcaptime(lc, name, RMAX, RMAX);
4560c3983b2SBen Gras rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR);
4570c3983b2SBen Gras rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX);
4580c3983b2SBen Gras break;
4590c3983b2SBen Gras case R_CSIZE:
460dba3562dSLionel Sambuc r.rlim_cur = login_getcapsize(lc, name, RCUR, RCUR);
461dba3562dSLionel Sambuc r.rlim_max = login_getcapsize(lc, name, RMAX, RMAX);
4620c3983b2SBen Gras rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR);
4630c3983b2SBen Gras rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX);
4640c3983b2SBen Gras break;
4650c3983b2SBen Gras case R_CNUMB:
466dba3562dSLionel Sambuc r.rlim_cur = login_getcapnum(lc, name, RCUR, RCUR);
467dba3562dSLionel Sambuc r.rlim_max = login_getcapnum(lc, name, RMAX, RMAX);
4680c3983b2SBen Gras rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR);
4690c3983b2SBen Gras rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX);
4700c3983b2SBen Gras break;
4710c3983b2SBen Gras default:
4720c3983b2SBen Gras syslog(LOG_ERR, "%s: invalid type %d setting resource limit %s",
4730c3983b2SBen Gras lc->lc_class, type, name);
4740c3983b2SBen Gras return (-1);
4750c3983b2SBen Gras }
4760c3983b2SBen Gras
4770c3983b2SBen Gras if (setrlimit(what, &rl)) {
4780c3983b2SBen Gras syslog(LOG_ERR, "%s: setting resource limit %s: %m",
4790c3983b2SBen Gras lc->lc_class, name);
4800c3983b2SBen Gras return (-1);
4810c3983b2SBen Gras }
4820c3983b2SBen Gras #undef RCUR
4830c3983b2SBen Gras #undef RMAX
4840c3983b2SBen Gras return (0);
4850c3983b2SBen Gras }
4860c3983b2SBen Gras
4870c3983b2SBen Gras static int
4880c3983b2SBen Gras /*ARGSUSED*/
envset(void * envp __unused,const char * name,const char * value,int overwrite)4890c3983b2SBen Gras envset(void *envp __unused, const char *name, const char *value, int overwrite)
4900c3983b2SBen Gras {
4910c3983b2SBen Gras return setenv(name, value, overwrite);
4920c3983b2SBen Gras }
4930c3983b2SBen Gras
4940c3983b2SBen Gras int
setuserenv(login_cap_t * lc,envfunc_t senv,void * envp)4950c3983b2SBen Gras setuserenv(login_cap_t *lc, envfunc_t senv, void *envp)
4960c3983b2SBen Gras {
4970c3983b2SBen Gras const char *stop = ", \t";
4980c3983b2SBen Gras size_t i, count;
4990c3983b2SBen Gras char *ptr;
5000c3983b2SBen Gras char **res;
5010c3983b2SBen Gras char *str = login_getcapstr(lc, "setenv", NULL, NULL);
5020c3983b2SBen Gras
5030c3983b2SBen Gras if (str == NULL || *str == '\0')
5040c3983b2SBen Gras return 0;
5050c3983b2SBen Gras
5060c3983b2SBen Gras /*
5070c3983b2SBen Gras * count the sub-strings, this may over-count since we don't
5080c3983b2SBen Gras * account for escaped delimiters.
5090c3983b2SBen Gras */
5100c3983b2SBen Gras for (i = 1, ptr = str; *ptr; i++) {
5110c3983b2SBen Gras ptr += strcspn(ptr, stop);
5120c3983b2SBen Gras if (*ptr)
5130c3983b2SBen Gras ptr++;
5140c3983b2SBen Gras }
5150c3983b2SBen Gras
5160c3983b2SBen Gras /* allocate ptr array and string */
5170c3983b2SBen Gras count = i;
518dba3562dSLionel Sambuc res = malloc(count * sizeof(*res) + strlen(str) + 1);
5190c3983b2SBen Gras
5200c3983b2SBen Gras if (!res)
5210c3983b2SBen Gras return -1;
5220c3983b2SBen Gras
5230c3983b2SBen Gras ptr = (char *)(void *)&res[count];
5240c3983b2SBen Gras (void)strcpy(ptr, str);
5250c3983b2SBen Gras
5260c3983b2SBen Gras /* split string */
5270c3983b2SBen Gras for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; )
5280c3983b2SBen Gras if (*res[i])
5290c3983b2SBen Gras i++;
5300c3983b2SBen Gras
5310c3983b2SBen Gras count = i;
5320c3983b2SBen Gras
5330c3983b2SBen Gras for (i = 0; i < count; i++) {
5340c3983b2SBen Gras if ((ptr = strchr(res[i], '=')) != NULL)
5350c3983b2SBen Gras *ptr++ = '\0';
5360c3983b2SBen Gras else
5370c3983b2SBen Gras ptr = NULL;
5380c3983b2SBen Gras (void)(*senv)(envp, res[i], ptr ? ptr : "", 1);
5390c3983b2SBen Gras }
5400c3983b2SBen Gras
5410c3983b2SBen Gras free(res);
5420c3983b2SBen Gras return 0;
5430c3983b2SBen Gras }
5440c3983b2SBen Gras
5450c3983b2SBen Gras int
setclasscontext(const char * class,u_int flags)5460c3983b2SBen Gras setclasscontext(const char *class, u_int flags)
5470c3983b2SBen Gras {
5480c3983b2SBen Gras int ret;
5490c3983b2SBen Gras login_cap_t *lc;
5500c3983b2SBen Gras
5510c3983b2SBen Gras flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK |
5520c3983b2SBen Gras LOGIN_SETPATH;
5530c3983b2SBen Gras
5540c3983b2SBen Gras lc = login_getclass(class);
5550c3983b2SBen Gras ret = lc ? setusercontext(lc, NULL, 0, flags) : -1;
5560c3983b2SBen Gras login_close(lc);
5570c3983b2SBen Gras return (ret);
5580c3983b2SBen Gras }
5590c3983b2SBen Gras
5600c3983b2SBen Gras int
setusercontext(login_cap_t * lc,struct passwd * pwd,uid_t uid,u_int flags)5610c3983b2SBen Gras setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags)
5620c3983b2SBen Gras {
5630c3983b2SBen Gras char per_user_tmp[MAXPATHLEN + 1];
5640c3983b2SBen Gras const char *component_name;
5650c3983b2SBen Gras login_cap_t *flc;
5660c3983b2SBen Gras quad_t p;
5670c3983b2SBen Gras int i;
5680c3983b2SBen Gras ssize_t len;
5690c3983b2SBen Gras
5700c3983b2SBen Gras flc = NULL;
5710c3983b2SBen Gras
5720c3983b2SBen Gras if (!lc)
5730c3983b2SBen Gras flc = lc = login_getclass(pwd ? pwd->pw_class : NULL);
574dba3562dSLionel Sambuc
5750c3983b2SBen Gras /*
5760c3983b2SBen Gras * Without the pwd entry being passed we cannot set either
5770c3983b2SBen Gras * the group or the login. We could complain about it.
5780c3983b2SBen Gras */
5790c3983b2SBen Gras if (pwd == NULL)
5800c3983b2SBen Gras flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
5810c3983b2SBen Gras
5820c3983b2SBen Gras #ifdef LOGIN_OSETGROUP
5830c3983b2SBen Gras if (pwd == NULL)
5840c3983b2SBen Gras flags &= ~LOGIN_OSETGROUP;
5850c3983b2SBen Gras if (flags & LOGIN_OSETGROUP)
5860c3983b2SBen Gras flags = (flags & ~LOGIN_OSETGROUP) | LOGIN_SETGROUP;
5870c3983b2SBen Gras #endif
5880c3983b2SBen Gras if (flags & LOGIN_SETRESOURCES)
5890c3983b2SBen Gras for (i = 0; r_list[i].name; ++i)
5900c3983b2SBen Gras (void)gsetrl(lc, r_list[i].what, r_list[i].name,
5910c3983b2SBen Gras r_list[i].type);
5920c3983b2SBen Gras
5930c3983b2SBen Gras if (flags & LOGIN_SETPRIORITY) {
5940c3983b2SBen Gras p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0);
5950c3983b2SBen Gras
5960c3983b2SBen Gras if (setpriority(PRIO_PROCESS, 0, (int)p) == -1)
5970c3983b2SBen Gras syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class);
5980c3983b2SBen Gras }
5990c3983b2SBen Gras
6000c3983b2SBen Gras if (flags & LOGIN_SETUMASK) {
6010c3983b2SBen Gras p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK,
6020c3983b2SBen Gras (quad_t)LOGIN_DEFUMASK);
6030c3983b2SBen Gras umask((mode_t)p);
6040c3983b2SBen Gras }
6050c3983b2SBen Gras
6060c3983b2SBen Gras if (flags & LOGIN_SETGID) {
6070c3983b2SBen Gras if (setgid(pwd->pw_gid) == -1) {
6080c3983b2SBen Gras syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
6090c3983b2SBen Gras login_close(flc);
6100c3983b2SBen Gras return (-1);
6110c3983b2SBen Gras }
6120c3983b2SBen Gras }
6130c3983b2SBen Gras
6140c3983b2SBen Gras if (flags & LOGIN_SETGROUPS) {
6150c3983b2SBen Gras if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
6160c3983b2SBen Gras syslog(LOG_ERR, "initgroups(%s,%d): %m",
6170c3983b2SBen Gras pwd->pw_name, pwd->pw_gid);
6180c3983b2SBen Gras login_close(flc);
6190c3983b2SBen Gras return (-1);
6200c3983b2SBen Gras }
6210c3983b2SBen Gras }
6220c3983b2SBen Gras
6230c3983b2SBen Gras /* Create per-user temporary directories if needed. */
6240c3983b2SBen Gras if ((len = readlink("/tmp", per_user_tmp,
6250c3983b2SBen Gras sizeof(per_user_tmp) - 6)) != -1) {
6260c3983b2SBen Gras
6270c3983b2SBen Gras static const char atuid[] = "/@ruid";
6280c3983b2SBen Gras char *lp;
6290c3983b2SBen Gras
6300c3983b2SBen Gras /* readlink does not nul-terminate the string */
6310c3983b2SBen Gras per_user_tmp[len] = '\0';
6320c3983b2SBen Gras
6330c3983b2SBen Gras /* Check if it's magic symlink. */
6340c3983b2SBen Gras lp = strstr(per_user_tmp, atuid);
6350c3983b2SBen Gras if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') {
6360c3983b2SBen Gras lp++;
6370c3983b2SBen Gras
6380c3983b2SBen Gras if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) {
6390c3983b2SBen Gras syslog(LOG_ERR, "real temporary path too long");
6400c3983b2SBen Gras login_close(flc);
6410c3983b2SBen Gras return (-1);
6420c3983b2SBen Gras }
6430c3983b2SBen Gras if (mkdir(per_user_tmp, S_IRWXU) != -1) {
6440c3983b2SBen Gras if (chown(per_user_tmp, pwd->pw_uid,
6450c3983b2SBen Gras pwd->pw_gid)) {
6460c3983b2SBen Gras component_name = "chown";
6470c3983b2SBen Gras goto out;
6480c3983b2SBen Gras }
6490c3983b2SBen Gras
6500c3983b2SBen Gras /*
6510c3983b2SBen Gras * Must set sticky bit for tmp directory, some
6520c3983b2SBen Gras * programs rely on this.
6530c3983b2SBen Gras */
6540c3983b2SBen Gras if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) {
6550c3983b2SBen Gras component_name = "chmod";
6560c3983b2SBen Gras goto out;
6570c3983b2SBen Gras }
6580c3983b2SBen Gras } else {
6590c3983b2SBen Gras if (errno != EEXIST) {
6600c3983b2SBen Gras component_name = "mkdir";
6610c3983b2SBen Gras goto out;
6620c3983b2SBen Gras } else {
6630c3983b2SBen Gras /*
6640c3983b2SBen Gras * We must ensure that we own the
6650c3983b2SBen Gras * directory and that is has the correct
6660c3983b2SBen Gras * permissions, otherwise a DOS attack
6670c3983b2SBen Gras * is possible.
6680c3983b2SBen Gras */
6690c3983b2SBen Gras struct stat sb;
6700c3983b2SBen Gras if (stat(per_user_tmp, &sb) == -1) {
6710c3983b2SBen Gras component_name = "stat";
6720c3983b2SBen Gras goto out;
6730c3983b2SBen Gras }
6740c3983b2SBen Gras
6750c3983b2SBen Gras if (sb.st_uid != pwd->pw_uid) {
6760c3983b2SBen Gras if (chown(per_user_tmp,
6770c3983b2SBen Gras pwd->pw_uid, pwd->pw_gid)) {
6780c3983b2SBen Gras component_name = "chown";
6790c3983b2SBen Gras goto out;
6800c3983b2SBen Gras }
6810c3983b2SBen Gras }
6820c3983b2SBen Gras
6830c3983b2SBen Gras if (sb.st_mode != (S_IRWXU | S_ISVTX)) {
6840c3983b2SBen Gras if (chmod(per_user_tmp,
6850c3983b2SBen Gras S_IRWXU | S_ISVTX)) {
6860c3983b2SBen Gras component_name = "chmod";
6870c3983b2SBen Gras goto out;
6880c3983b2SBen Gras }
6890c3983b2SBen Gras }
6900c3983b2SBen Gras }
6910c3983b2SBen Gras }
6920c3983b2SBen Gras }
6930c3983b2SBen Gras }
6940c3983b2SBen Gras errno = 0;
6950c3983b2SBen Gras
69684d9c625SLionel Sambuc #if !defined(__minix)
6970c3983b2SBen Gras if (flags & LOGIN_SETLOGIN)
6980c3983b2SBen Gras if (setlogin(pwd->pw_name) == -1) {
6990c3983b2SBen Gras syslog(LOG_ERR, "setlogin(%s) failure: %m",
7000c3983b2SBen Gras pwd->pw_name);
7010c3983b2SBen Gras login_close(flc);
7020c3983b2SBen Gras return (-1);
7030c3983b2SBen Gras }
70484d9c625SLionel Sambuc #endif /* !defined(__minix) */
7050c3983b2SBen Gras
7060c3983b2SBen Gras if (flags & LOGIN_SETUSER)
7070c3983b2SBen Gras if (setuid(uid) == -1) {
7080c3983b2SBen Gras syslog(LOG_ERR, "setuid(%d): %m", uid);
7090c3983b2SBen Gras login_close(flc);
7100c3983b2SBen Gras return (-1);
7110c3983b2SBen Gras }
7120c3983b2SBen Gras
7130c3983b2SBen Gras if (flags & LOGIN_SETENV)
7140c3983b2SBen Gras setuserenv(lc, envset, NULL);
7150c3983b2SBen Gras
7160c3983b2SBen Gras if (flags & LOGIN_SETPATH)
7170c3983b2SBen Gras setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL);
7180c3983b2SBen Gras
7190c3983b2SBen Gras login_close(flc);
7200c3983b2SBen Gras return (0);
7210c3983b2SBen Gras
7220c3983b2SBen Gras out:
7230c3983b2SBen Gras if (component_name != NULL) {
7240c3983b2SBen Gras syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp);
7250c3983b2SBen Gras login_close(flc);
7260c3983b2SBen Gras return (-1);
7270c3983b2SBen Gras } else {
7280c3983b2SBen Gras syslog(LOG_ERR, "%s: %m", per_user_tmp);
7290c3983b2SBen Gras login_close(flc);
7300c3983b2SBen Gras return (-1);
7310c3983b2SBen Gras }
7320c3983b2SBen Gras }
7330c3983b2SBen Gras
7340c3983b2SBen Gras void
setuserpath(login_cap_t * lc,const char * home,envfunc_t senv,void * envp)7350c3983b2SBen Gras setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp)
7360c3983b2SBen Gras {
7370c3983b2SBen Gras size_t hlen, plen;
7380c3983b2SBen Gras int cnt = 0;
7390c3983b2SBen Gras char *path;
7400c3983b2SBen Gras const char *cpath;
7410c3983b2SBen Gras char *p, *q;
7420c3983b2SBen Gras
7430c3983b2SBen Gras _DIAGASSERT(home != NULL);
7440c3983b2SBen Gras
7450c3983b2SBen Gras hlen = strlen(home);
7460c3983b2SBen Gras
7470c3983b2SBen Gras p = path = login_getcapstr(lc, "path", NULL, NULL);
7480c3983b2SBen Gras if (p) {
7490c3983b2SBen Gras while (*p)
7500c3983b2SBen Gras if (*p++ == '~')
7510c3983b2SBen Gras ++cnt;
7520c3983b2SBen Gras plen = (p - path) + cnt * (hlen + 1) + 1;
7530c3983b2SBen Gras p = path;
7540c3983b2SBen Gras q = path = malloc(plen);
7550c3983b2SBen Gras if (q) {
7560c3983b2SBen Gras while (*p) {
7570c3983b2SBen Gras p += strspn(p, " \t");
7580c3983b2SBen Gras if (*p == '\0')
7590c3983b2SBen Gras break;
7600c3983b2SBen Gras plen = strcspn(p, " \t");
7610c3983b2SBen Gras if (hlen == 0 && *p == '~') {
7620c3983b2SBen Gras p += plen;
7630c3983b2SBen Gras continue;
7640c3983b2SBen Gras }
7650c3983b2SBen Gras if (q != path)
7660c3983b2SBen Gras *q++ = ':';
7670c3983b2SBen Gras if (*p == '~') {
7680c3983b2SBen Gras strcpy(q, home);
7690c3983b2SBen Gras q += hlen;
7700c3983b2SBen Gras ++p;
7710c3983b2SBen Gras --plen;
7720c3983b2SBen Gras }
7730c3983b2SBen Gras memcpy(q, p, plen);
7740c3983b2SBen Gras p += plen;
7750c3983b2SBen Gras q += plen;
7760c3983b2SBen Gras }
7770c3983b2SBen Gras *q = '\0';
7780c3983b2SBen Gras cpath = path;
7790c3983b2SBen Gras } else
7800c3983b2SBen Gras cpath = _PATH_DEFPATH;
7810c3983b2SBen Gras } else
7820c3983b2SBen Gras cpath = _PATH_DEFPATH;
7830c3983b2SBen Gras if ((*senv)(envp, "PATH", cpath, 1))
7840c3983b2SBen Gras warn("could not set PATH");
7850c3983b2SBen Gras }
7860c3983b2SBen Gras
7870c3983b2SBen Gras /*
7880c3983b2SBen Gras * Convert an expression of the following forms
7890c3983b2SBen Gras * 1) A number.
7900c3983b2SBen Gras * 2) A number followed by a b (mult by 512).
7910c3983b2SBen Gras * 3) A number followed by a k (mult by 1024).
7920c3983b2SBen Gras * 5) A number followed by a m (mult by 1024 * 1024).
7930c3983b2SBen Gras * 6) A number followed by a g (mult by 1024 * 1024 * 1024).
7940c3983b2SBen Gras * 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024).
7950c3983b2SBen Gras * 8) Two or more numbers (with/without k,b,m,g, or t).
7960c3983b2SBen Gras * separated by x (also * for backwards compatibility), specifying
7970c3983b2SBen Gras * the product of the indicated values.
7980c3983b2SBen Gras */
7990c3983b2SBen Gras static u_quad_t
strtosize(const char * str,char ** endptr,int radix)8000c3983b2SBen Gras strtosize(const char *str, char **endptr, int radix)
8010c3983b2SBen Gras {
8020c3983b2SBen Gras u_quad_t num, num2;
8030c3983b2SBen Gras char *expr, *expr2;
8040c3983b2SBen Gras
8050c3983b2SBen Gras _DIAGASSERT(str != NULL);
8060c3983b2SBen Gras /* endptr may be NULL */
8070c3983b2SBen Gras
8080c3983b2SBen Gras errno = 0;
8090c3983b2SBen Gras num = strtouq(str, &expr, radix);
8100c3983b2SBen Gras if (errno || expr == str) {
8110c3983b2SBen Gras if (endptr)
8120c3983b2SBen Gras *endptr = expr;
8130c3983b2SBen Gras return (num);
8140c3983b2SBen Gras }
8150c3983b2SBen Gras
8160c3983b2SBen Gras switch(*expr) {
8170c3983b2SBen Gras case 'b': case 'B':
8180c3983b2SBen Gras num = multiply(num, (u_quad_t)512);
8190c3983b2SBen Gras ++expr;
8200c3983b2SBen Gras break;
8210c3983b2SBen Gras case 'k': case 'K':
8220c3983b2SBen Gras num = multiply(num, (u_quad_t)1024);
8230c3983b2SBen Gras ++expr;
8240c3983b2SBen Gras break;
8250c3983b2SBen Gras case 'm': case 'M':
8260c3983b2SBen Gras num = multiply(num, (u_quad_t)1024 * 1024);
8270c3983b2SBen Gras ++expr;
8280c3983b2SBen Gras break;
8290c3983b2SBen Gras case 'g': case 'G':
8300c3983b2SBen Gras num = multiply(num, (u_quad_t)1024 * 1024 * 1024);
8310c3983b2SBen Gras ++expr;
8320c3983b2SBen Gras break;
8330c3983b2SBen Gras case 't': case 'T':
8340c3983b2SBen Gras num = multiply(num, (u_quad_t)1024 * 1024);
8350c3983b2SBen Gras num = multiply(num, (u_quad_t)1024 * 1024);
8360c3983b2SBen Gras ++expr;
8370c3983b2SBen Gras break;
8380c3983b2SBen Gras }
8390c3983b2SBen Gras
8400c3983b2SBen Gras if (errno)
8410c3983b2SBen Gras goto erange;
8420c3983b2SBen Gras
8430c3983b2SBen Gras switch(*expr) {
8440c3983b2SBen Gras case '*': /* Backward compatible. */
8450c3983b2SBen Gras case 'x':
8460c3983b2SBen Gras num2 = strtosize(expr+1, &expr2, radix);
8470c3983b2SBen Gras if (errno) {
8480c3983b2SBen Gras expr = expr2;
8490c3983b2SBen Gras goto erange;
8500c3983b2SBen Gras }
8510c3983b2SBen Gras
8520c3983b2SBen Gras if (expr2 == expr + 1) {
8530c3983b2SBen Gras if (endptr)
8540c3983b2SBen Gras *endptr = expr;
8550c3983b2SBen Gras return (num);
8560c3983b2SBen Gras }
8570c3983b2SBen Gras expr = expr2;
8580c3983b2SBen Gras num = multiply(num, num2);
8590c3983b2SBen Gras if (errno)
8600c3983b2SBen Gras goto erange;
8610c3983b2SBen Gras break;
8620c3983b2SBen Gras }
8630c3983b2SBen Gras if (endptr)
8640c3983b2SBen Gras *endptr = expr;
8650c3983b2SBen Gras return (num);
8660c3983b2SBen Gras erange:
8670c3983b2SBen Gras if (endptr)
8680c3983b2SBen Gras *endptr = expr;
8690c3983b2SBen Gras errno = ERANGE;
8700c3983b2SBen Gras return (UQUAD_MAX);
8710c3983b2SBen Gras }
8720c3983b2SBen Gras
8730c3983b2SBen Gras static u_quad_t
strtolimit(const char * str,char ** endptr,int radix)8740c3983b2SBen Gras strtolimit(const char *str, char **endptr, int radix)
8750c3983b2SBen Gras {
8760c3983b2SBen Gras
8770c3983b2SBen Gras _DIAGASSERT(str != NULL);
8780c3983b2SBen Gras /* endptr may be NULL */
8790c3983b2SBen Gras
8800c3983b2SBen Gras if (isinfinite(str)) {
8810c3983b2SBen Gras if (endptr)
8820c3983b2SBen Gras *endptr = (char *)__UNCONST(str) + strlen(str);
8830c3983b2SBen Gras return ((u_quad_t)RLIM_INFINITY);
8840c3983b2SBen Gras }
8850c3983b2SBen Gras return (strtosize(str, endptr, radix));
8860c3983b2SBen Gras }
8870c3983b2SBen Gras
8880c3983b2SBen Gras static int
isinfinite(const char * s)8890c3983b2SBen Gras isinfinite(const char *s)
8900c3983b2SBen Gras {
8910c3983b2SBen Gras static const char *infs[] = {
8920c3983b2SBen Gras "infinity",
8930c3983b2SBen Gras "inf",
8940c3983b2SBen Gras "unlimited",
8950c3983b2SBen Gras "unlimit",
8960c3983b2SBen Gras NULL
8970c3983b2SBen Gras };
8980c3983b2SBen Gras const char **i;
8990c3983b2SBen Gras
9000c3983b2SBen Gras _DIAGASSERT(s != NULL);
9010c3983b2SBen Gras
9020c3983b2SBen Gras for (i = infs; *i; i++) {
9030c3983b2SBen Gras if (!strcasecmp(s, *i))
9040c3983b2SBen Gras return 1;
9050c3983b2SBen Gras }
9060c3983b2SBen Gras return 0;
9070c3983b2SBen Gras }
9080c3983b2SBen Gras
9090c3983b2SBen Gras static u_quad_t
multiply(u_quad_t n1,u_quad_t n2)9100c3983b2SBen Gras multiply(u_quad_t n1, u_quad_t n2)
9110c3983b2SBen Gras {
9120c3983b2SBen Gras static int bpw = 0;
9130c3983b2SBen Gras u_quad_t m;
9140c3983b2SBen Gras u_quad_t r;
9150c3983b2SBen Gras int b1, b2;
9160c3983b2SBen Gras
9170c3983b2SBen Gras /*
9180c3983b2SBen Gras * Get rid of the simple cases
9190c3983b2SBen Gras */
9200c3983b2SBen Gras if (n1 == 0 || n2 == 0)
9210c3983b2SBen Gras return (0);
9220c3983b2SBen Gras if (n1 == 1)
9230c3983b2SBen Gras return (n2);
9240c3983b2SBen Gras if (n2 == 1)
9250c3983b2SBen Gras return (n1);
9260c3983b2SBen Gras
9270c3983b2SBen Gras /*
9280c3983b2SBen Gras * sizeof() returns number of bytes needed for storage.
9290c3983b2SBen Gras * This may be different from the actual number of useful bits.
9300c3983b2SBen Gras */
9310c3983b2SBen Gras if (!bpw) {
9320c3983b2SBen Gras bpw = sizeof(u_quad_t) * 8;
9330c3983b2SBen Gras while (((u_quad_t)1 << (bpw-1)) == 0)
9340c3983b2SBen Gras --bpw;
9350c3983b2SBen Gras }
9360c3983b2SBen Gras
9370c3983b2SBen Gras /*
9380c3983b2SBen Gras * First check the magnitude of each number. If the sum of the
9390c3983b2SBen Gras * magnatude is way to high, reject the number. (If this test
9400c3983b2SBen Gras * is not done then the first multiply below may overflow.)
9410c3983b2SBen Gras */
9420c3983b2SBen Gras for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
9430c3983b2SBen Gras ;
9440c3983b2SBen Gras for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
9450c3983b2SBen Gras ;
9460c3983b2SBen Gras if (b1 + b2 - 2 > bpw) {
9470c3983b2SBen Gras errno = ERANGE;
9480c3983b2SBen Gras return (UQUAD_MAX);
9490c3983b2SBen Gras }
9500c3983b2SBen Gras
9510c3983b2SBen Gras /*
9520c3983b2SBen Gras * Decompose the multiplication to be:
9530c3983b2SBen Gras * h1 = n1 & ~1
9540c3983b2SBen Gras * h2 = n2 & ~1
9550c3983b2SBen Gras * l1 = n1 & 1
9560c3983b2SBen Gras * l2 = n2 & 1
9570c3983b2SBen Gras * (h1 + l1) * (h2 + l2)
9580c3983b2SBen Gras * (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
9590c3983b2SBen Gras *
9600c3983b2SBen Gras * Since h1 && h2 do not have the low bit set, we can then say:
9610c3983b2SBen Gras *
9620c3983b2SBen Gras * (h1>>1 * h2>>1 * 4) + ...
9630c3983b2SBen Gras *
9640c3983b2SBen Gras * So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
9650c3983b2SBen Gras * overflow.
9660c3983b2SBen Gras *
9670c3983b2SBen Gras * Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
9680c3983b2SBen Gras * then adding in residual amout will cause an overflow.
9690c3983b2SBen Gras */
9700c3983b2SBen Gras
9710c3983b2SBen Gras m = (n1 >> 1) * (n2 >> 1);
9720c3983b2SBen Gras
9730c3983b2SBen Gras if (m >= ((u_quad_t)1 << (bpw-2))) {
9740c3983b2SBen Gras errno = ERANGE;
9750c3983b2SBen Gras return (UQUAD_MAX);
9760c3983b2SBen Gras }
9770c3983b2SBen Gras
9780c3983b2SBen Gras m *= 4;
9790c3983b2SBen Gras
9800c3983b2SBen Gras r = (n1 & n2 & 1)
9810c3983b2SBen Gras + (n2 & 1) * (n1 & ~(u_quad_t)1)
9820c3983b2SBen Gras + (n1 & 1) * (n2 & ~(u_quad_t)1);
9830c3983b2SBen Gras
9840c3983b2SBen Gras if ((u_quad_t)(m + r) < m) {
9850c3983b2SBen Gras errno = ERANGE;
9860c3983b2SBen Gras return (UQUAD_MAX);
9870c3983b2SBen Gras }
9880c3983b2SBen Gras m += r;
9890c3983b2SBen Gras
9900c3983b2SBen Gras return (m);
9910c3983b2SBen Gras }
992