1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2000 Markus Friedl. All rights reserved. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 5*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 6*0Sstevel@tonic-gate * are met: 7*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 8*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 9*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 10*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 11*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate /* 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "includes.h" 30*0Sstevel@tonic-gate RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $"); 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include "misc.h" 35*0Sstevel@tonic-gate #include "log.h" 36*0Sstevel@tonic-gate #include "xmalloc.h" 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* remove newline at end of string */ 39*0Sstevel@tonic-gate char * 40*0Sstevel@tonic-gate chop(char *s) 41*0Sstevel@tonic-gate { 42*0Sstevel@tonic-gate char *t = s; 43*0Sstevel@tonic-gate while (*t) { 44*0Sstevel@tonic-gate if (*t == '\n' || *t == '\r') { 45*0Sstevel@tonic-gate *t = '\0'; 46*0Sstevel@tonic-gate return s; 47*0Sstevel@tonic-gate } 48*0Sstevel@tonic-gate t++; 49*0Sstevel@tonic-gate } 50*0Sstevel@tonic-gate return s; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate } 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate /* set/unset filedescriptor to non-blocking */ 55*0Sstevel@tonic-gate void 56*0Sstevel@tonic-gate set_nonblock(int fd) 57*0Sstevel@tonic-gate { 58*0Sstevel@tonic-gate int val; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate val = fcntl(fd, F_GETFL, 0); 61*0Sstevel@tonic-gate if (val < 0) { 62*0Sstevel@tonic-gate error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 63*0Sstevel@tonic-gate return; 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate if (val & O_NONBLOCK) { 66*0Sstevel@tonic-gate debug2("fd %d is O_NONBLOCK", fd); 67*0Sstevel@tonic-gate return; 68*0Sstevel@tonic-gate } 69*0Sstevel@tonic-gate debug("fd %d setting O_NONBLOCK", fd); 70*0Sstevel@tonic-gate val |= O_NONBLOCK; 71*0Sstevel@tonic-gate if (fcntl(fd, F_SETFL, val) == -1) 72*0Sstevel@tonic-gate debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 73*0Sstevel@tonic-gate fd, strerror(errno)); 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate void 77*0Sstevel@tonic-gate unset_nonblock(int fd) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate int val; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate val = fcntl(fd, F_GETFL, 0); 82*0Sstevel@tonic-gate if (val < 0) { 83*0Sstevel@tonic-gate error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 84*0Sstevel@tonic-gate return; 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate if (!(val & O_NONBLOCK)) { 87*0Sstevel@tonic-gate debug2("fd %d is not O_NONBLOCK", fd); 88*0Sstevel@tonic-gate return; 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate debug("fd %d clearing O_NONBLOCK", fd); 91*0Sstevel@tonic-gate val &= ~O_NONBLOCK; 92*0Sstevel@tonic-gate if (fcntl(fd, F_SETFL, val) == -1) 93*0Sstevel@tonic-gate debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 94*0Sstevel@tonic-gate fd, strerror(errno)); 95*0Sstevel@tonic-gate } 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate /* disable nagle on socket */ 98*0Sstevel@tonic-gate void 99*0Sstevel@tonic-gate set_nodelay(int fd) 100*0Sstevel@tonic-gate { 101*0Sstevel@tonic-gate int opt; 102*0Sstevel@tonic-gate socklen_t optlen; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate optlen = sizeof opt; 105*0Sstevel@tonic-gate if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 106*0Sstevel@tonic-gate error("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 107*0Sstevel@tonic-gate return; 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate if (opt == 1) { 110*0Sstevel@tonic-gate debug2("fd %d is TCP_NODELAY", fd); 111*0Sstevel@tonic-gate return; 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate opt = 1; 114*0Sstevel@tonic-gate debug("fd %d setting TCP_NODELAY", fd); 115*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 116*0Sstevel@tonic-gate error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* Characters considered whitespace in strsep calls. */ 120*0Sstevel@tonic-gate #define WHITESPACE " \t\r\n" 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* return next token in configuration line */ 123*0Sstevel@tonic-gate char * 124*0Sstevel@tonic-gate strdelim(char **s) 125*0Sstevel@tonic-gate { 126*0Sstevel@tonic-gate char *old; 127*0Sstevel@tonic-gate int wspace = 0; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (*s == NULL) 130*0Sstevel@tonic-gate return NULL; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate old = *s; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate *s = strpbrk(*s, WHITESPACE "="); 135*0Sstevel@tonic-gate if (*s == NULL) 136*0Sstevel@tonic-gate return (old); 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate /* Allow only one '=' to be skipped */ 139*0Sstevel@tonic-gate if (*s[0] == '=') 140*0Sstevel@tonic-gate wspace = 1; 141*0Sstevel@tonic-gate *s[0] = '\0'; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate *s += strspn(*s + 1, WHITESPACE) + 1; 144*0Sstevel@tonic-gate if (*s[0] == '=' && !wspace) 145*0Sstevel@tonic-gate *s += strspn(*s + 1, WHITESPACE) + 1; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate return (old); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate struct passwd * 151*0Sstevel@tonic-gate pwcopy(struct passwd *pw) 152*0Sstevel@tonic-gate { 153*0Sstevel@tonic-gate struct passwd *copy = xmalloc(sizeof(*copy)); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate memset(copy, 0, sizeof(*copy)); 156*0Sstevel@tonic-gate copy->pw_name = xstrdup(pw->pw_name); 157*0Sstevel@tonic-gate copy->pw_passwd = xstrdup(pw->pw_passwd); 158*0Sstevel@tonic-gate copy->pw_gecos = xstrdup(pw->pw_gecos); 159*0Sstevel@tonic-gate copy->pw_uid = pw->pw_uid; 160*0Sstevel@tonic-gate copy->pw_gid = pw->pw_gid; 161*0Sstevel@tonic-gate #ifdef HAVE_PW_EXPIRE_IN_PASSWD 162*0Sstevel@tonic-gate copy->pw_expire = pw->pw_expire; 163*0Sstevel@tonic-gate #endif 164*0Sstevel@tonic-gate #ifdef HAVE_PW_CHANGE_IN_PASSWD 165*0Sstevel@tonic-gate copy->pw_change = pw->pw_change; 166*0Sstevel@tonic-gate #endif 167*0Sstevel@tonic-gate #ifdef HAVE_PW_CLASS_IN_PASSWD 168*0Sstevel@tonic-gate copy->pw_class = xstrdup(pw->pw_class); 169*0Sstevel@tonic-gate #endif 170*0Sstevel@tonic-gate copy->pw_dir = xstrdup(pw->pw_dir); 171*0Sstevel@tonic-gate copy->pw_shell = xstrdup(pw->pw_shell); 172*0Sstevel@tonic-gate return copy; 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate void 176*0Sstevel@tonic-gate pwfree(struct passwd **pw) 177*0Sstevel@tonic-gate { 178*0Sstevel@tonic-gate struct passwd *p; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (pw == NULL || *pw == NULL) 181*0Sstevel@tonic-gate return; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate p = *pw; 184*0Sstevel@tonic-gate *pw = NULL; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate xfree(p->pw_name); 187*0Sstevel@tonic-gate xfree(p->pw_passwd); 188*0Sstevel@tonic-gate xfree(p->pw_gecos); 189*0Sstevel@tonic-gate #ifdef HAVE_PW_CLASS_IN_PASSWD 190*0Sstevel@tonic-gate xfree(p->pw_class); 191*0Sstevel@tonic-gate #endif 192*0Sstevel@tonic-gate xfree(p->pw_dir); 193*0Sstevel@tonic-gate xfree(p->pw_shell); 194*0Sstevel@tonic-gate xfree(p); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * Convert ASCII string to TCP/IP port number. 199*0Sstevel@tonic-gate * Port must be >0 and <=65535. 200*0Sstevel@tonic-gate * Return 0 if invalid. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate int 203*0Sstevel@tonic-gate a2port(const char *s) 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate long port; 206*0Sstevel@tonic-gate char *endp; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate errno = 0; 209*0Sstevel@tonic-gate port = strtol(s, &endp, 0); 210*0Sstevel@tonic-gate if (s == endp || *endp != '\0' || 211*0Sstevel@tonic-gate (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 212*0Sstevel@tonic-gate port <= 0 || port > 65535) 213*0Sstevel@tonic-gate return 0; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate return port; 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate #define SECONDS 1 219*0Sstevel@tonic-gate #define MINUTES (SECONDS * 60) 220*0Sstevel@tonic-gate #define HOURS (MINUTES * 60) 221*0Sstevel@tonic-gate #define DAYS (HOURS * 24) 222*0Sstevel@tonic-gate #define WEEKS (DAYS * 7) 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * Convert a time string into seconds; format is 226*0Sstevel@tonic-gate * a sequence of: 227*0Sstevel@tonic-gate * time[qualifier] 228*0Sstevel@tonic-gate * 229*0Sstevel@tonic-gate * Valid time qualifiers are: 230*0Sstevel@tonic-gate * <none> seconds 231*0Sstevel@tonic-gate * s|S seconds 232*0Sstevel@tonic-gate * m|M minutes 233*0Sstevel@tonic-gate * h|H hours 234*0Sstevel@tonic-gate * d|D days 235*0Sstevel@tonic-gate * w|W weeks 236*0Sstevel@tonic-gate * 237*0Sstevel@tonic-gate * Examples: 238*0Sstevel@tonic-gate * 90m 90 minutes 239*0Sstevel@tonic-gate * 1h30m 90 minutes 240*0Sstevel@tonic-gate * 2d 2 days 241*0Sstevel@tonic-gate * 1w 1 week 242*0Sstevel@tonic-gate * 243*0Sstevel@tonic-gate * Return -1 if time string is invalid. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate long 246*0Sstevel@tonic-gate convtime(const char *s) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate long total, secs; 249*0Sstevel@tonic-gate const char *p; 250*0Sstevel@tonic-gate char *endp; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate errno = 0; 253*0Sstevel@tonic-gate total = 0; 254*0Sstevel@tonic-gate p = s; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (p == NULL || *p == '\0') 257*0Sstevel@tonic-gate return -1; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate while (*p) { 260*0Sstevel@tonic-gate secs = strtol(p, &endp, 10); 261*0Sstevel@tonic-gate if (p == endp || 262*0Sstevel@tonic-gate (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 263*0Sstevel@tonic-gate secs < 0) 264*0Sstevel@tonic-gate return -1; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate switch (*endp++) { 267*0Sstevel@tonic-gate case '\0': 268*0Sstevel@tonic-gate endp--; 269*0Sstevel@tonic-gate break; 270*0Sstevel@tonic-gate case 's': 271*0Sstevel@tonic-gate case 'S': 272*0Sstevel@tonic-gate break; 273*0Sstevel@tonic-gate case 'm': 274*0Sstevel@tonic-gate case 'M': 275*0Sstevel@tonic-gate secs *= MINUTES; 276*0Sstevel@tonic-gate break; 277*0Sstevel@tonic-gate case 'h': 278*0Sstevel@tonic-gate case 'H': 279*0Sstevel@tonic-gate secs *= HOURS; 280*0Sstevel@tonic-gate break; 281*0Sstevel@tonic-gate case 'd': 282*0Sstevel@tonic-gate case 'D': 283*0Sstevel@tonic-gate secs *= DAYS; 284*0Sstevel@tonic-gate break; 285*0Sstevel@tonic-gate case 'w': 286*0Sstevel@tonic-gate case 'W': 287*0Sstevel@tonic-gate secs *= WEEKS; 288*0Sstevel@tonic-gate break; 289*0Sstevel@tonic-gate default: 290*0Sstevel@tonic-gate return -1; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate total += secs; 293*0Sstevel@tonic-gate if (total < 0) 294*0Sstevel@tonic-gate return -1; 295*0Sstevel@tonic-gate p = endp; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate return total; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate char * 302*0Sstevel@tonic-gate cleanhostname(char *host) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate if (*host == '[' && host[strlen(host) - 1] == ']') { 305*0Sstevel@tonic-gate host[strlen(host) - 1] = '\0'; 306*0Sstevel@tonic-gate return (host + 1); 307*0Sstevel@tonic-gate } else 308*0Sstevel@tonic-gate return host; 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate char * 312*0Sstevel@tonic-gate colon(char *cp) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate int flag = 0; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate if (*cp == ':') /* Leading colon is part of file name. */ 317*0Sstevel@tonic-gate return (0); 318*0Sstevel@tonic-gate if (*cp == '[') 319*0Sstevel@tonic-gate flag = 1; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate for (; *cp; ++cp) { 322*0Sstevel@tonic-gate if (*cp == '@' && *(cp+1) == '[') 323*0Sstevel@tonic-gate flag = 1; 324*0Sstevel@tonic-gate if (*cp == ']' && *(cp+1) == ':' && flag) 325*0Sstevel@tonic-gate return (cp+1); 326*0Sstevel@tonic-gate if (*cp == ':' && !flag) 327*0Sstevel@tonic-gate return (cp); 328*0Sstevel@tonic-gate if (*cp == '/') 329*0Sstevel@tonic-gate return (0); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate return (0); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* function to assist building execv() arguments */ 335*0Sstevel@tonic-gate /* PRINTFLIKE2 */ 336*0Sstevel@tonic-gate void 337*0Sstevel@tonic-gate addargs(arglist *args, char *fmt, ...) 338*0Sstevel@tonic-gate { 339*0Sstevel@tonic-gate va_list ap; 340*0Sstevel@tonic-gate char buf[1024]; 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate va_start(ap, fmt); 343*0Sstevel@tonic-gate vsnprintf(buf, sizeof(buf), fmt, ap); 344*0Sstevel@tonic-gate va_end(ap); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate if (args->list == NULL) { 347*0Sstevel@tonic-gate args->nalloc = 32; 348*0Sstevel@tonic-gate args->num = 0; 349*0Sstevel@tonic-gate } else if (args->num+2 >= args->nalloc) 350*0Sstevel@tonic-gate args->nalloc *= 2; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate args->list = xrealloc(args->list, args->nalloc * sizeof(char *)); 353*0Sstevel@tonic-gate args->list[args->num++] = xstrdup(buf); 354*0Sstevel@tonic-gate args->list[args->num] = NULL; 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate mysig_t 358*0Sstevel@tonic-gate mysignal(int sig, mysig_t act) 359*0Sstevel@tonic-gate { 360*0Sstevel@tonic-gate #ifdef HAVE_SIGACTION 361*0Sstevel@tonic-gate struct sigaction sa, osa; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (sigaction(sig, NULL, &osa) == -1) 364*0Sstevel@tonic-gate return (mysig_t) -1; 365*0Sstevel@tonic-gate if (osa.sa_handler != act) { 366*0Sstevel@tonic-gate memset(&sa, 0, sizeof(sa)); 367*0Sstevel@tonic-gate sigemptyset(&sa.sa_mask); 368*0Sstevel@tonic-gate sa.sa_flags = 0; 369*0Sstevel@tonic-gate #if defined(SA_INTERRUPT) 370*0Sstevel@tonic-gate if (sig == SIGALRM) 371*0Sstevel@tonic-gate sa.sa_flags |= SA_INTERRUPT; 372*0Sstevel@tonic-gate #endif 373*0Sstevel@tonic-gate sa.sa_handler = act; 374*0Sstevel@tonic-gate if (sigaction(sig, &sa, NULL) == -1) 375*0Sstevel@tonic-gate return (mysig_t) -1; 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate return (osa.sa_handler); 378*0Sstevel@tonic-gate #else 379*0Sstevel@tonic-gate return (signal(sig, act)); 380*0Sstevel@tonic-gate #endif 381*0Sstevel@tonic-gate } 382