xref: /minix3/lib/libutil/login_cap.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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