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