xref: /onnv-gate/usr/src/cmd/ssh/libssh/common/misc.c (revision 9139:84e06a454b4b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
50Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
60Sstevel@tonic-gate  * are met:
70Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
80Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
90Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
100Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
110Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
140Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
150Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
160Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
170Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
180Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
190Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
200Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
220Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate /*
25*9139SJan.Pechanec@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
260Sstevel@tonic-gate  * Use is subject to license terms.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "includes.h"
300Sstevel@tonic-gate RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $");
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include "misc.h"
330Sstevel@tonic-gate #include "log.h"
340Sstevel@tonic-gate #include "xmalloc.h"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /* remove newline at end of string */
370Sstevel@tonic-gate char *
chop(char * s)380Sstevel@tonic-gate chop(char *s)
390Sstevel@tonic-gate {
400Sstevel@tonic-gate 	char *t = s;
410Sstevel@tonic-gate 	while (*t) {
420Sstevel@tonic-gate 		if (*t == '\n' || *t == '\r') {
430Sstevel@tonic-gate 			*t = '\0';
440Sstevel@tonic-gate 			return s;
450Sstevel@tonic-gate 		}
460Sstevel@tonic-gate 		t++;
470Sstevel@tonic-gate 	}
480Sstevel@tonic-gate 	return s;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate }
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* set/unset filedescriptor to non-blocking */
530Sstevel@tonic-gate void
set_nonblock(int fd)540Sstevel@tonic-gate set_nonblock(int fd)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate 	int val;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	val = fcntl(fd, F_GETFL, 0);
590Sstevel@tonic-gate 	if (val < 0) {
600Sstevel@tonic-gate 		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
610Sstevel@tonic-gate 		return;
620Sstevel@tonic-gate 	}
630Sstevel@tonic-gate 	if (val & O_NONBLOCK) {
640Sstevel@tonic-gate 		debug2("fd %d is O_NONBLOCK", fd);
650Sstevel@tonic-gate 		return;
660Sstevel@tonic-gate 	}
670Sstevel@tonic-gate 	debug("fd %d setting O_NONBLOCK", fd);
680Sstevel@tonic-gate 	val |= O_NONBLOCK;
690Sstevel@tonic-gate 	if (fcntl(fd, F_SETFL, val) == -1)
700Sstevel@tonic-gate 		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
710Sstevel@tonic-gate 		    fd, strerror(errno));
720Sstevel@tonic-gate }
730Sstevel@tonic-gate 
740Sstevel@tonic-gate void
unset_nonblock(int fd)750Sstevel@tonic-gate unset_nonblock(int fd)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	int val;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	val = fcntl(fd, F_GETFL, 0);
800Sstevel@tonic-gate 	if (val < 0) {
810Sstevel@tonic-gate 		error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
820Sstevel@tonic-gate 		return;
830Sstevel@tonic-gate 	}
840Sstevel@tonic-gate 	if (!(val & O_NONBLOCK)) {
850Sstevel@tonic-gate 		debug2("fd %d is not O_NONBLOCK", fd);
860Sstevel@tonic-gate 		return;
870Sstevel@tonic-gate 	}
880Sstevel@tonic-gate 	debug("fd %d clearing O_NONBLOCK", fd);
890Sstevel@tonic-gate 	val &= ~O_NONBLOCK;
900Sstevel@tonic-gate 	if (fcntl(fd, F_SETFL, val) == -1)
910Sstevel@tonic-gate 		debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s",
920Sstevel@tonic-gate 		    fd, strerror(errno));
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /* disable nagle on socket */
960Sstevel@tonic-gate void
set_nodelay(int fd)970Sstevel@tonic-gate set_nodelay(int fd)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	int opt;
1000Sstevel@tonic-gate 	socklen_t optlen;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	optlen = sizeof opt;
1030Sstevel@tonic-gate 	if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
1040Sstevel@tonic-gate 		error("getsockopt TCP_NODELAY: %.100s", strerror(errno));
1050Sstevel@tonic-gate 		return;
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 	if (opt == 1) {
1080Sstevel@tonic-gate 		debug2("fd %d is TCP_NODELAY", fd);
1090Sstevel@tonic-gate 		return;
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 	opt = 1;
1120Sstevel@tonic-gate 	debug("fd %d setting TCP_NODELAY", fd);
1130Sstevel@tonic-gate 	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
1140Sstevel@tonic-gate 		error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /* Characters considered whitespace in strsep calls. */
1180Sstevel@tonic-gate #define WHITESPACE " \t\r\n"
1190Sstevel@tonic-gate 
1203946Sjp161948 /*
1213946Sjp161948  * Function returns a pointer to the 1st token on the line. Such a token can
1223946Sjp161948  * be an empty string in the case of '*s' equal to " value". It changes the
1233946Sjp161948  * first whitespace token or '=' character after the 1st token to '\0'. Upon
1243946Sjp161948  * return it changes '*s' to point to the first character of the next token.
1253946Sjp161948  * That token may be an empty string if the 1st token was followed only by
1263946Sjp161948  * whitespace or it could be a NULL pointer if the line contained one token
1273946Sjp161948  * only.
1283946Sjp161948  */
1290Sstevel@tonic-gate char *
strdelim(char ** s)1300Sstevel@tonic-gate strdelim(char **s)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate 	char *old;
1330Sstevel@tonic-gate 	int wspace = 0;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	if (*s == NULL)
1360Sstevel@tonic-gate 		return NULL;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	old = *s;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	*s = strpbrk(*s, WHITESPACE "=");
1410Sstevel@tonic-gate 	if (*s == NULL)
1420Sstevel@tonic-gate 		return (old);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	/* Allow only one '=' to be skipped */
1450Sstevel@tonic-gate 	if (*s[0] == '=')
1460Sstevel@tonic-gate 		wspace = 1;
1470Sstevel@tonic-gate 	*s[0] = '\0';
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	*s += strspn(*s + 1, WHITESPACE) + 1;
1500Sstevel@tonic-gate 	if (*s[0] == '=' && !wspace)
1510Sstevel@tonic-gate 		*s += strspn(*s + 1, WHITESPACE) + 1;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	return (old);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate struct passwd *
pwcopy(struct passwd * pw)1570Sstevel@tonic-gate pwcopy(struct passwd *pw)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	struct passwd *copy = xmalloc(sizeof(*copy));
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	memset(copy, 0, sizeof(*copy));
1620Sstevel@tonic-gate 	copy->pw_name = xstrdup(pw->pw_name);
1630Sstevel@tonic-gate 	copy->pw_passwd = xstrdup(pw->pw_passwd);
1640Sstevel@tonic-gate 	copy->pw_gecos = xstrdup(pw->pw_gecos);
1650Sstevel@tonic-gate 	copy->pw_uid = pw->pw_uid;
1660Sstevel@tonic-gate 	copy->pw_gid = pw->pw_gid;
1670Sstevel@tonic-gate #ifdef HAVE_PW_EXPIRE_IN_PASSWD
1680Sstevel@tonic-gate 	copy->pw_expire = pw->pw_expire;
1690Sstevel@tonic-gate #endif
1700Sstevel@tonic-gate #ifdef HAVE_PW_CHANGE_IN_PASSWD
1710Sstevel@tonic-gate 	copy->pw_change = pw->pw_change;
1720Sstevel@tonic-gate #endif
1730Sstevel@tonic-gate #ifdef HAVE_PW_CLASS_IN_PASSWD
1740Sstevel@tonic-gate 	copy->pw_class = xstrdup(pw->pw_class);
1750Sstevel@tonic-gate #endif
1760Sstevel@tonic-gate 	copy->pw_dir = xstrdup(pw->pw_dir);
1770Sstevel@tonic-gate 	copy->pw_shell = xstrdup(pw->pw_shell);
1780Sstevel@tonic-gate 	return copy;
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate void
pwfree(struct passwd ** pw)1820Sstevel@tonic-gate pwfree(struct passwd **pw)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	struct passwd *p;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if (pw == NULL || *pw == NULL)
1870Sstevel@tonic-gate 		return;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	p = *pw;
1900Sstevel@tonic-gate 	*pw = NULL;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	xfree(p->pw_name);
1930Sstevel@tonic-gate 	xfree(p->pw_passwd);
1940Sstevel@tonic-gate 	xfree(p->pw_gecos);
1950Sstevel@tonic-gate #ifdef HAVE_PW_CLASS_IN_PASSWD
1960Sstevel@tonic-gate 	xfree(p->pw_class);
1970Sstevel@tonic-gate #endif
1980Sstevel@tonic-gate 	xfree(p->pw_dir);
1990Sstevel@tonic-gate 	xfree(p->pw_shell);
2000Sstevel@tonic-gate 	xfree(p);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * Convert ASCII string to TCP/IP port number.
2050Sstevel@tonic-gate  * Port must be >0 and <=65535.
2060Sstevel@tonic-gate  * Return 0 if invalid.
2070Sstevel@tonic-gate  */
2080Sstevel@tonic-gate int
a2port(const char * s)2090Sstevel@tonic-gate a2port(const char *s)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate 	long port;
2120Sstevel@tonic-gate 	char *endp;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	errno = 0;
2150Sstevel@tonic-gate 	port = strtol(s, &endp, 0);
2160Sstevel@tonic-gate 	if (s == endp || *endp != '\0' ||
2170Sstevel@tonic-gate 	    (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
2180Sstevel@tonic-gate 	    port <= 0 || port > 65535)
2190Sstevel@tonic-gate 		return 0;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	return port;
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate #define SECONDS		1
2250Sstevel@tonic-gate #define MINUTES		(SECONDS * 60)
2260Sstevel@tonic-gate #define HOURS		(MINUTES * 60)
2270Sstevel@tonic-gate #define DAYS		(HOURS * 24)
2280Sstevel@tonic-gate #define WEEKS		(DAYS * 7)
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * Convert a time string into seconds; format is
2320Sstevel@tonic-gate  * a sequence of:
2330Sstevel@tonic-gate  *      time[qualifier]
2340Sstevel@tonic-gate  *
2350Sstevel@tonic-gate  * Valid time qualifiers are:
2360Sstevel@tonic-gate  *      <none>  seconds
2370Sstevel@tonic-gate  *      s|S     seconds
2380Sstevel@tonic-gate  *      m|M     minutes
2390Sstevel@tonic-gate  *      h|H     hours
2400Sstevel@tonic-gate  *      d|D     days
2410Sstevel@tonic-gate  *      w|W     weeks
2420Sstevel@tonic-gate  *
2430Sstevel@tonic-gate  * Examples:
2440Sstevel@tonic-gate  *      90m     90 minutes
2450Sstevel@tonic-gate  *      1h30m   90 minutes
2460Sstevel@tonic-gate  *      2d      2 days
2470Sstevel@tonic-gate  *      1w      1 week
2480Sstevel@tonic-gate  *
2490Sstevel@tonic-gate  * Return -1 if time string is invalid.
2500Sstevel@tonic-gate  */
2510Sstevel@tonic-gate long
convtime(const char * s)2520Sstevel@tonic-gate convtime(const char *s)
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	long total, secs;
2550Sstevel@tonic-gate 	const char *p;
2560Sstevel@tonic-gate 	char *endp;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	errno = 0;
2590Sstevel@tonic-gate 	total = 0;
2600Sstevel@tonic-gate 	p = s;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (p == NULL || *p == '\0')
2630Sstevel@tonic-gate 		return -1;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	while (*p) {
2660Sstevel@tonic-gate 		secs = strtol(p, &endp, 10);
2670Sstevel@tonic-gate 		if (p == endp ||
2680Sstevel@tonic-gate 		    (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
2690Sstevel@tonic-gate 		    secs < 0)
2700Sstevel@tonic-gate 			return -1;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		switch (*endp++) {
2730Sstevel@tonic-gate 		case '\0':
2740Sstevel@tonic-gate 			endp--;
2750Sstevel@tonic-gate 			break;
2760Sstevel@tonic-gate 		case 's':
2770Sstevel@tonic-gate 		case 'S':
2780Sstevel@tonic-gate 			break;
2790Sstevel@tonic-gate 		case 'm':
2800Sstevel@tonic-gate 		case 'M':
2810Sstevel@tonic-gate 			secs *= MINUTES;
2820Sstevel@tonic-gate 			break;
2830Sstevel@tonic-gate 		case 'h':
2840Sstevel@tonic-gate 		case 'H':
2850Sstevel@tonic-gate 			secs *= HOURS;
2860Sstevel@tonic-gate 			break;
2870Sstevel@tonic-gate 		case 'd':
2880Sstevel@tonic-gate 		case 'D':
2890Sstevel@tonic-gate 			secs *= DAYS;
2900Sstevel@tonic-gate 			break;
2910Sstevel@tonic-gate 		case 'w':
2920Sstevel@tonic-gate 		case 'W':
2930Sstevel@tonic-gate 			secs *= WEEKS;
2940Sstevel@tonic-gate 			break;
2950Sstevel@tonic-gate 		default:
2960Sstevel@tonic-gate 			return -1;
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		total += secs;
2990Sstevel@tonic-gate 		if (total < 0)
3000Sstevel@tonic-gate 			return -1;
3010Sstevel@tonic-gate 		p = endp;
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	return total;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3075334Sjp161948 /*
3085334Sjp161948  * Search for next delimiter between hostnames/addresses and ports.
3095334Sjp161948  * Argument may be modified (for termination).
3105334Sjp161948  * Returns *cp if parsing succeeds.
3115334Sjp161948  * *cp is set to the start of the next delimiter, if one was found.
3125334Sjp161948  * If this is the last field, *cp is set to NULL.
3135334Sjp161948  */
3145334Sjp161948 char *
hpdelim(char ** cp)3155334Sjp161948 hpdelim(char **cp)
3165334Sjp161948 {
3175334Sjp161948 	char *s, *old;
3185334Sjp161948 
3195334Sjp161948 	if (cp == NULL || *cp == NULL)
3205334Sjp161948 		return NULL;
3215334Sjp161948 
3225334Sjp161948 	old = s = *cp;
3235334Sjp161948 	if (*s == '[') {
3245334Sjp161948 		if ((s = strchr(s, ']')) == NULL)
3255334Sjp161948 			return NULL;
3265334Sjp161948 		else
3275334Sjp161948 			s++;
3285334Sjp161948 	} else if ((s = strpbrk(s, ":/")) == NULL)
3295334Sjp161948 		s = *cp + strlen(*cp); /* skip to end (see first case below) */
3305334Sjp161948 
3315334Sjp161948 	switch (*s) {
3325334Sjp161948 	case '\0':
3335334Sjp161948 		*cp = NULL;	/* no more fields*/
3345334Sjp161948 		break;
3355334Sjp161948 
3365334Sjp161948 	case ':':
3375334Sjp161948 	case '/':
3385334Sjp161948 		*s = '\0';	/* terminate */
3395334Sjp161948 		*cp = s + 1;
3405334Sjp161948 		break;
3415334Sjp161948 
3425334Sjp161948 	default:
3435334Sjp161948 		return NULL;
3445334Sjp161948 	}
3455334Sjp161948 
3465334Sjp161948 	return old;
3475334Sjp161948 }
3485334Sjp161948 
3490Sstevel@tonic-gate char *
cleanhostname(char * host)3500Sstevel@tonic-gate cleanhostname(char *host)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	if (*host == '[' && host[strlen(host) - 1] == ']') {
3530Sstevel@tonic-gate 		host[strlen(host) - 1] = '\0';
3540Sstevel@tonic-gate 		return (host + 1);
3550Sstevel@tonic-gate 	} else
3560Sstevel@tonic-gate 		return host;
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate char *
colon(char * cp)3600Sstevel@tonic-gate colon(char *cp)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	int flag = 0;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if (*cp == ':')		/* Leading colon is part of file name. */
3650Sstevel@tonic-gate 		return (0);
3660Sstevel@tonic-gate 	if (*cp == '[')
3670Sstevel@tonic-gate 		flag = 1;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	for (; *cp; ++cp) {
3700Sstevel@tonic-gate 		if (*cp == '@' && *(cp+1) == '[')
3710Sstevel@tonic-gate 			flag = 1;
3720Sstevel@tonic-gate 		if (*cp == ']' && *(cp+1) == ':' && flag)
3730Sstevel@tonic-gate 			return (cp+1);
3740Sstevel@tonic-gate 		if (*cp == ':' && !flag)
3750Sstevel@tonic-gate 			return (cp);
3760Sstevel@tonic-gate 		if (*cp == '/')
3770Sstevel@tonic-gate 			return (0);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	return (0);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate /* function to assist building execv() arguments */
3830Sstevel@tonic-gate /* PRINTFLIKE2 */
3840Sstevel@tonic-gate void
addargs(arglist * args,char * fmt,...)3850Sstevel@tonic-gate addargs(arglist *args, char *fmt, ...)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	va_list ap;
3880Sstevel@tonic-gate 	char buf[1024];
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	va_start(ap, fmt);
3910Sstevel@tonic-gate 	vsnprintf(buf, sizeof(buf), fmt, ap);
3920Sstevel@tonic-gate 	va_end(ap);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (args->list == NULL) {
3950Sstevel@tonic-gate 		args->nalloc = 32;
3960Sstevel@tonic-gate 		args->num = 0;
3970Sstevel@tonic-gate 	} else if (args->num+2 >= args->nalloc)
3980Sstevel@tonic-gate 		args->nalloc *= 2;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
4010Sstevel@tonic-gate 	args->list[args->num++] = xstrdup(buf);
4020Sstevel@tonic-gate 	args->list[args->num] = NULL;
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4052780Sjp161948 void
replacearg(arglist * args,u_int which,char * fmt,...)4065087Sjp161948 replacearg(arglist *args, u_int which, char *fmt, ...)
4075087Sjp161948 {
4085087Sjp161948 	va_list ap;
4095087Sjp161948 	char *cp;
4105087Sjp161948 	int r;
4115087Sjp161948 
4125087Sjp161948 	va_start(ap, fmt);
4135087Sjp161948 	r = vasprintf(&cp, fmt, ap);
4145087Sjp161948 	va_end(ap);
4155087Sjp161948 	if (r == -1)
4165087Sjp161948 		fatal("replacearg: argument too long");
4175087Sjp161948 
4185087Sjp161948 	if (which >= args->num)
4195087Sjp161948 		fatal("replacearg: tried to replace invalid arg %d >= %d",
4205087Sjp161948 		    which, args->num);
4215087Sjp161948 	xfree(args->list[which]);
4225087Sjp161948 	args->list[which] = cp;
4235087Sjp161948 }
4245087Sjp161948 
4255087Sjp161948 void
freeargs(arglist * args)4262780Sjp161948 freeargs(arglist *args)
4272780Sjp161948 {
4282780Sjp161948 	u_int i;
4292780Sjp161948 
4302780Sjp161948 	if (args->list != NULL) {
4312780Sjp161948 		for (i = 0; i < args->num; i++)
4322780Sjp161948 			xfree(args->list[i]);
4332780Sjp161948 		xfree(args->list);
4342780Sjp161948 		args->nalloc = args->num = 0;
4352780Sjp161948 		args->list = NULL;
4362780Sjp161948 	}
4372780Sjp161948 }
4382780Sjp161948 
4395087Sjp161948 /*
440*9139SJan.Pechanec@Sun.COM  * Expand a string with a set of %[char] escapes. A number of escapes may be
441*9139SJan.Pechanec@Sun.COM  * specified as (char *escape_chars, char *replacement) pairs. The list must
442*9139SJan.Pechanec@Sun.COM  * be terminated by a NULL escape_char. Returns replaced string in memory
443*9139SJan.Pechanec@Sun.COM  * allocated by xmalloc.
444*9139SJan.Pechanec@Sun.COM  */
445*9139SJan.Pechanec@Sun.COM char *
percent_expand(const char * string,...)446*9139SJan.Pechanec@Sun.COM percent_expand(const char *string, ...)
447*9139SJan.Pechanec@Sun.COM {
448*9139SJan.Pechanec@Sun.COM #define EXPAND_MAX_KEYS	16
449*9139SJan.Pechanec@Sun.COM 	struct {
450*9139SJan.Pechanec@Sun.COM 		const char *key;
451*9139SJan.Pechanec@Sun.COM 		const char *repl;
452*9139SJan.Pechanec@Sun.COM 	} keys[EXPAND_MAX_KEYS];
453*9139SJan.Pechanec@Sun.COM 	u_int num_keys, i, j;
454*9139SJan.Pechanec@Sun.COM 	char buf[4096];
455*9139SJan.Pechanec@Sun.COM 	va_list ap;
456*9139SJan.Pechanec@Sun.COM 
457*9139SJan.Pechanec@Sun.COM 	/* Gather keys */
458*9139SJan.Pechanec@Sun.COM 	va_start(ap, string);
459*9139SJan.Pechanec@Sun.COM 	for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
460*9139SJan.Pechanec@Sun.COM 		keys[num_keys].key = va_arg(ap, char *);
461*9139SJan.Pechanec@Sun.COM 		if (keys[num_keys].key == NULL)
462*9139SJan.Pechanec@Sun.COM 			break;
463*9139SJan.Pechanec@Sun.COM 		keys[num_keys].repl = va_arg(ap, char *);
464*9139SJan.Pechanec@Sun.COM 		if (keys[num_keys].repl == NULL)
465*9139SJan.Pechanec@Sun.COM 			fatal("percent_expand: NULL replacement");
466*9139SJan.Pechanec@Sun.COM 	}
467*9139SJan.Pechanec@Sun.COM 	va_end(ap);
468*9139SJan.Pechanec@Sun.COM 
469*9139SJan.Pechanec@Sun.COM 	if (num_keys >= EXPAND_MAX_KEYS)
470*9139SJan.Pechanec@Sun.COM 		fatal("percent_expand: too many keys");
471*9139SJan.Pechanec@Sun.COM 
472*9139SJan.Pechanec@Sun.COM 	/* Expand string */
473*9139SJan.Pechanec@Sun.COM 	*buf = '\0';
474*9139SJan.Pechanec@Sun.COM 	for (i = 0; *string != '\0'; string++) {
475*9139SJan.Pechanec@Sun.COM 		if (*string != '%') {
476*9139SJan.Pechanec@Sun.COM  append:
477*9139SJan.Pechanec@Sun.COM 			buf[i++] = *string;
478*9139SJan.Pechanec@Sun.COM 			if (i >= sizeof(buf))
479*9139SJan.Pechanec@Sun.COM 				fatal("percent_expand: string too long");
480*9139SJan.Pechanec@Sun.COM 			buf[i] = '\0';
481*9139SJan.Pechanec@Sun.COM 			continue;
482*9139SJan.Pechanec@Sun.COM 		}
483*9139SJan.Pechanec@Sun.COM 		string++;
484*9139SJan.Pechanec@Sun.COM 		if (*string == '%')
485*9139SJan.Pechanec@Sun.COM 			goto append;
486*9139SJan.Pechanec@Sun.COM 		for (j = 0; j < num_keys; j++) {
487*9139SJan.Pechanec@Sun.COM 			if (strchr(keys[j].key, *string) != NULL) {
488*9139SJan.Pechanec@Sun.COM 				i = strlcat(buf, keys[j].repl, sizeof(buf));
489*9139SJan.Pechanec@Sun.COM 				if (i >= sizeof(buf))
490*9139SJan.Pechanec@Sun.COM 					fatal("percent_expand: string too long");
491*9139SJan.Pechanec@Sun.COM 				break;
492*9139SJan.Pechanec@Sun.COM 			}
493*9139SJan.Pechanec@Sun.COM 		}
494*9139SJan.Pechanec@Sun.COM 		if (j >= num_keys)
495*9139SJan.Pechanec@Sun.COM 			fatal("percent_expand: unknown key %%%c", *string);
496*9139SJan.Pechanec@Sun.COM 	}
497*9139SJan.Pechanec@Sun.COM 	return (xstrdup(buf));
498*9139SJan.Pechanec@Sun.COM #undef EXPAND_MAX_KEYS
499*9139SJan.Pechanec@Sun.COM }
500*9139SJan.Pechanec@Sun.COM 
501*9139SJan.Pechanec@Sun.COM /*
5025087Sjp161948  * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null,
5035087Sjp161948  * do not touch those that are already open.
5045087Sjp161948  */
5055087Sjp161948 void
sanitise_stdfd(void)5065087Sjp161948 sanitise_stdfd(void)
5075087Sjp161948 {
5085087Sjp161948 	int nullfd, dupfd;
5095087Sjp161948 
5105087Sjp161948 	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
5115087Sjp161948 		fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno));
5125087Sjp161948 		exit(1);
5135087Sjp161948 	}
5145087Sjp161948 	while (++dupfd <= 2) {
5155087Sjp161948 		/* Only clobber closed fds */
5165087Sjp161948 		if (fcntl(dupfd, F_GETFL, 0) >= 0)
5175087Sjp161948 			continue;
5185087Sjp161948 		if (dup2(nullfd, dupfd) == -1) {
5195087Sjp161948 			fprintf(stderr, "dup2: %s", strerror(errno));
5205087Sjp161948 			exit(1);
5215087Sjp161948 		}
5225087Sjp161948 	}
5235087Sjp161948 	if (nullfd > 2)
5245087Sjp161948 		close(nullfd);
5255087Sjp161948 }
5265087Sjp161948 
5274907Sjp161948 char *
tohex(const void * vp,size_t l)5284907Sjp161948 tohex(const void *vp, size_t l)
5294907Sjp161948 {
5304907Sjp161948 	const u_char *p = (const u_char *)vp;
5314907Sjp161948 	char b[3], *r;
5324907Sjp161948 	size_t i, hl;
5334907Sjp161948 
5344907Sjp161948 	if (l > 65536)
5354907Sjp161948 		return xstrdup("tohex: length > 65536");
5364907Sjp161948 
5374907Sjp161948 	hl = l * 2 + 1;
5384907Sjp161948 	r = xcalloc(1, hl);
5394907Sjp161948 	for (i = 0; i < l; i++) {
5404907Sjp161948 		snprintf(b, sizeof(b), "%02x", p[i]);
5414907Sjp161948 		strlcat(r, b, hl);
5424907Sjp161948 	}
5434907Sjp161948 	return (r);
5444907Sjp161948 }
5454907Sjp161948 
5465087Sjp161948 u_int64_t
get_u64(const void * vp)5475087Sjp161948 get_u64(const void *vp)
5485087Sjp161948 {
5495087Sjp161948 	const u_char *p = (const u_char *)vp;
5505087Sjp161948 	u_int64_t v;
5515087Sjp161948 
5525087Sjp161948 	v  = (u_int64_t)p[0] << 56;
5535087Sjp161948 	v |= (u_int64_t)p[1] << 48;
5545087Sjp161948 	v |= (u_int64_t)p[2] << 40;
5555087Sjp161948 	v |= (u_int64_t)p[3] << 32;
5565087Sjp161948 	v |= (u_int64_t)p[4] << 24;
5575087Sjp161948 	v |= (u_int64_t)p[5] << 16;
5585087Sjp161948 	v |= (u_int64_t)p[6] << 8;
5595087Sjp161948 	v |= (u_int64_t)p[7];
5605087Sjp161948 
5615087Sjp161948 	return (v);
5625087Sjp161948 }
5635087Sjp161948 
5645087Sjp161948 u_int32_t
get_u32(const void * vp)5655087Sjp161948 get_u32(const void *vp)
5665087Sjp161948 {
5675087Sjp161948 	const u_char *p = (const u_char *)vp;
5685087Sjp161948 	u_int32_t v;
5695087Sjp161948 
5705087Sjp161948 	v  = (u_int32_t)p[0] << 24;
5715087Sjp161948 	v |= (u_int32_t)p[1] << 16;
5725087Sjp161948 	v |= (u_int32_t)p[2] << 8;
5735087Sjp161948 	v |= (u_int32_t)p[3];
5745087Sjp161948 
5755087Sjp161948 	return (v);
5765087Sjp161948 }
5775087Sjp161948 
5785087Sjp161948 u_int16_t
get_u16(const void * vp)5795087Sjp161948 get_u16(const void *vp)
5805087Sjp161948 {
5815087Sjp161948 	const u_char *p = (const u_char *)vp;
5825087Sjp161948 	u_int16_t v;
5835087Sjp161948 
5845087Sjp161948 	v  = (u_int16_t)p[0] << 8;
5855087Sjp161948 	v |= (u_int16_t)p[1];
5865087Sjp161948 
5875087Sjp161948 	return (v);
5885087Sjp161948 }
5895087Sjp161948 
5905087Sjp161948 void
put_u64(void * vp,u_int64_t v)5915087Sjp161948 put_u64(void *vp, u_int64_t v)
5925087Sjp161948 {
5935087Sjp161948 	u_char *p = (u_char *)vp;
5945087Sjp161948 
5955087Sjp161948 	p[0] = (u_char)(v >> 56) & 0xff;
5965087Sjp161948 	p[1] = (u_char)(v >> 48) & 0xff;
5975087Sjp161948 	p[2] = (u_char)(v >> 40) & 0xff;
5985087Sjp161948 	p[3] = (u_char)(v >> 32) & 0xff;
5995087Sjp161948 	p[4] = (u_char)(v >> 24) & 0xff;
6005087Sjp161948 	p[5] = (u_char)(v >> 16) & 0xff;
6015087Sjp161948 	p[6] = (u_char)(v >> 8) & 0xff;
6025087Sjp161948 	p[7] = (u_char)v & 0xff;
6035087Sjp161948 }
6045087Sjp161948 
6055087Sjp161948 void
put_u32(void * vp,u_int32_t v)6065087Sjp161948 put_u32(void *vp, u_int32_t v)
6075087Sjp161948 {
6085087Sjp161948 	u_char *p = (u_char *)vp;
6095087Sjp161948 
6105087Sjp161948 	p[0] = (u_char)(v >> 24) & 0xff;
6115087Sjp161948 	p[1] = (u_char)(v >> 16) & 0xff;
6125087Sjp161948 	p[2] = (u_char)(v >> 8) & 0xff;
6135087Sjp161948 	p[3] = (u_char)v & 0xff;
6145087Sjp161948 }
6155087Sjp161948 
6165087Sjp161948 
6175087Sjp161948 void
put_u16(void * vp,u_int16_t v)6185087Sjp161948 put_u16(void *vp, u_int16_t v)
6195087Sjp161948 {
6205087Sjp161948 	u_char *p = (u_char *)vp;
6215087Sjp161948 
6225087Sjp161948 	p[0] = (u_char)(v >> 8) & 0xff;
6235087Sjp161948 	p[1] = (u_char)v & 0xff;
6245087Sjp161948 }
6255087Sjp161948 
6260Sstevel@tonic-gate mysig_t
mysignal(int sig,mysig_t act)6270Sstevel@tonic-gate mysignal(int sig, mysig_t act)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate #ifdef HAVE_SIGACTION
6300Sstevel@tonic-gate 	struct sigaction sa, osa;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if (sigaction(sig, NULL, &osa) == -1)
6330Sstevel@tonic-gate 		return (mysig_t) -1;
6340Sstevel@tonic-gate 	if (osa.sa_handler != act) {
6350Sstevel@tonic-gate 		memset(&sa, 0, sizeof(sa));
6360Sstevel@tonic-gate 		sigemptyset(&sa.sa_mask);
6370Sstevel@tonic-gate 		sa.sa_flags = 0;
6380Sstevel@tonic-gate #if defined(SA_INTERRUPT)
6390Sstevel@tonic-gate 		if (sig == SIGALRM)
6400Sstevel@tonic-gate 			sa.sa_flags |= SA_INTERRUPT;
6410Sstevel@tonic-gate #endif
6420Sstevel@tonic-gate 		sa.sa_handler = act;
6430Sstevel@tonic-gate 		if (sigaction(sig, &sa, NULL) == -1)
6440Sstevel@tonic-gate 			return (mysig_t) -1;
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 	return (osa.sa_handler);
6470Sstevel@tonic-gate #else
6480Sstevel@tonic-gate 	return (signal(sig, act));
6490Sstevel@tonic-gate #endif
6500Sstevel@tonic-gate }
6514958Sjp161948 
6524958Sjp161948 /*
6534958Sjp161948  * Return true if argument is one of "yes", "true", "no" or "false". If
6544958Sjp161948  * 'active' is 0 than we are in a non-matching Host section of the
6554958Sjp161948  * configuration file so we check the syntax but will not set the value of
6564958Sjp161948  * '*option'. Otherwise we set its value if not already set.
6574958Sjp161948  */
6584958Sjp161948 int
get_yes_no_flag(int * option,const char * arg,const char * filename,int linenum,int active)6594958Sjp161948 get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum,
6604958Sjp161948     int active)
6614958Sjp161948 {
6624958Sjp161948 	int value = -1;
6634958Sjp161948 
6644958Sjp161948 	if (arg == NULL || *arg == '\0')
6654958Sjp161948 		fatal("%.200s line %d: Missing argument.", filename, linenum);
6664958Sjp161948 	if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
6674958Sjp161948 		value = 1;
6684958Sjp161948 	else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
6694958Sjp161948 		value = 0;
6704958Sjp161948 
6714958Sjp161948 	if (active && *option == -1 && value != -1)
6724958Sjp161948 		*option = value;
6734958Sjp161948 
6744958Sjp161948 	return (value != -1);
6754958Sjp161948 }
6765266Sjp161948 
6775266Sjp161948 /*
6785266Sjp161948  * Convert a string to lowercase. The string returned is an internally allocated
6795266Sjp161948  * one so the consumer of this function is not expected to change it or free it.
6805266Sjp161948  */
6815266Sjp161948 char *
tolowercase(const char * s)6825266Sjp161948 tolowercase(const char *s)
6835266Sjp161948 {
6845266Sjp161948 	int i, len;
6855266Sjp161948 	static int lenret = 0;
6865266Sjp161948 	static char *ret = NULL;
6875266Sjp161948 
6885266Sjp161948 	/* allocate a new string if the old one it not long enough to store s */
6895266Sjp161948 	len = strlen(s) + 1;
6905266Sjp161948 	if (len > lenret) {
6915266Sjp161948 		if (ret != NULL)
6925266Sjp161948 			xfree(ret);
6935266Sjp161948 		ret = xmalloc(len);
6945266Sjp161948 		lenret = len;
6955266Sjp161948 	}
6965266Sjp161948 
6975266Sjp161948 	/* process the string including the ending '\0' */
6985266Sjp161948 	for (i = 0; i < len; ++i)
6995266Sjp161948 		ret[i] = tolower(s[i]);
7005266Sjp161948 
7015266Sjp161948 	return (ret);
7025266Sjp161948 }
703