1323124Sdes/* $OpenBSD: misc.c,v 1.105 2016/07/15 00:24:30 djm Exp $ */ 276259Sgreen/* 376259Sgreen * Copyright (c) 2000 Markus Friedl. All rights reserved. 4162852Sdes * Copyright (c) 2005,2006 Damien Miller. All rights reserved. 576259Sgreen * 676259Sgreen * Redistribution and use in source and binary forms, with or without 776259Sgreen * modification, are permitted provided that the following conditions 876259Sgreen * are met: 976259Sgreen * 1. Redistributions of source code must retain the above copyright 1076259Sgreen * notice, this list of conditions and the following disclaimer. 1176259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1276259Sgreen * notice, this list of conditions and the following disclaimer in the 1376259Sgreen * documentation and/or other materials provided with the distribution. 1476259Sgreen * 1576259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1676259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1776259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1876259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1976259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2076259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2176259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2276259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2376259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2476259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2576259Sgreen */ 2676259Sgreen 2776259Sgreen#include "includes.h" 2876259Sgreen 29162852Sdes#include <sys/types.h> 30162852Sdes#include <sys/ioctl.h> 31162852Sdes#include <sys/socket.h> 32296781Sdes#include <sys/time.h> 33295367Sdes#include <sys/un.h> 34162852Sdes 35295367Sdes#include <limits.h> 36162852Sdes#include <stdarg.h> 37162852Sdes#include <stdio.h> 38162852Sdes#include <stdlib.h> 39162852Sdes#include <string.h> 40221420Sdes#include <time.h> 41162852Sdes#include <unistd.h> 42162852Sdes 43162852Sdes#include <netinet/in.h> 44221420Sdes#include <netinet/in_systm.h> 45221420Sdes#include <netinet/ip.h> 46162852Sdes#include <netinet/tcp.h> 47162852Sdes 48262566Sdes#include <ctype.h> 49162852Sdes#include <errno.h> 50162852Sdes#include <fcntl.h> 51181111Sdes#include <netdb.h> 52162852Sdes#ifdef HAVE_PATHS_H 53162852Sdes# include <paths.h> 54162852Sdes#include <pwd.h> 55162852Sdes#endif 56157016Sdes#ifdef SSH_TUN_OPENBSD 57157016Sdes#include <net/if.h> 58157016Sdes#endif 59157016Sdes 60162852Sdes#include "xmalloc.h" 6176259Sgreen#include "misc.h" 6276259Sgreen#include "log.h" 63162852Sdes#include "ssh.h" 6476259Sgreen 6592555Sdes/* remove newline at end of string */ 6676259Sgreenchar * 6776259Sgreenchop(char *s) 6876259Sgreen{ 6976259Sgreen char *t = s; 7076259Sgreen while (*t) { 7192555Sdes if (*t == '\n' || *t == '\r') { 7276259Sgreen *t = '\0'; 7376259Sgreen return s; 7476259Sgreen } 7576259Sgreen t++; 7676259Sgreen } 7776259Sgreen return s; 7876259Sgreen 7976259Sgreen} 8076259Sgreen 8192555Sdes/* set/unset filedescriptor to non-blocking */ 82137015Sdesint 8376259Sgreenset_nonblock(int fd) 8476259Sgreen{ 8576259Sgreen int val; 8692555Sdes 87323124Sdes val = fcntl(fd, F_GETFL); 8876259Sgreen if (val < 0) { 89323124Sdes error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 90137015Sdes return (-1); 9176259Sgreen } 9276259Sgreen if (val & O_NONBLOCK) { 93137015Sdes debug3("fd %d is O_NONBLOCK", fd); 94137015Sdes return (0); 9576259Sgreen } 96124208Sdes debug2("fd %d setting O_NONBLOCK", fd); 9776259Sgreen val |= O_NONBLOCK; 98137015Sdes if (fcntl(fd, F_SETFL, val) == -1) { 99137015Sdes debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 100137015Sdes strerror(errno)); 101137015Sdes return (-1); 102137015Sdes } 103137015Sdes return (0); 10476259Sgreen} 10576259Sgreen 106137015Sdesint 10792555Sdesunset_nonblock(int fd) 10892555Sdes{ 10992555Sdes int val; 11092555Sdes 111323124Sdes val = fcntl(fd, F_GETFL); 11292555Sdes if (val < 0) { 113323124Sdes error("fcntl(%d, F_GETFL): %s", fd, strerror(errno)); 114137015Sdes return (-1); 11592555Sdes } 11692555Sdes if (!(val & O_NONBLOCK)) { 117137015Sdes debug3("fd %d is not O_NONBLOCK", fd); 118137015Sdes return (0); 11992555Sdes } 12092555Sdes debug("fd %d clearing O_NONBLOCK", fd); 12192555Sdes val &= ~O_NONBLOCK; 122137015Sdes if (fcntl(fd, F_SETFL, val) == -1) { 123137015Sdes debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 12492555Sdes fd, strerror(errno)); 125137015Sdes return (-1); 126137015Sdes } 127137015Sdes return (0); 12892555Sdes} 12992555Sdes 130181111Sdesconst char * 131181111Sdesssh_gai_strerror(int gaierr) 132181111Sdes{ 133255767Sdes if (gaierr == EAI_SYSTEM && errno != 0) 134181111Sdes return strerror(errno); 135181111Sdes return gai_strerror(gaierr); 136181111Sdes} 137181111Sdes 13892555Sdes/* disable nagle on socket */ 13992555Sdesvoid 14092555Sdesset_nodelay(int fd) 14192555Sdes{ 14292555Sdes int opt; 14392555Sdes socklen_t optlen; 14492555Sdes 14592555Sdes optlen = sizeof opt; 14692555Sdes if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 147126274Sdes debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 14892555Sdes return; 14992555Sdes } 15092555Sdes if (opt == 1) { 15192555Sdes debug2("fd %d is TCP_NODELAY", fd); 15292555Sdes return; 15392555Sdes } 15492555Sdes opt = 1; 155113908Sdes debug2("fd %d setting TCP_NODELAY", fd); 15692555Sdes if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 15792555Sdes error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 15892555Sdes} 15992555Sdes 16076259Sgreen/* Characters considered whitespace in strsep calls. */ 16176259Sgreen#define WHITESPACE " \t\r\n" 162162852Sdes#define QUOTE "\"" 16376259Sgreen 16492555Sdes/* return next token in configuration line */ 16576259Sgreenchar * 16676259Sgreenstrdelim(char **s) 16776259Sgreen{ 16876259Sgreen char *old; 16976259Sgreen int wspace = 0; 17076259Sgreen 17176259Sgreen if (*s == NULL) 17276259Sgreen return NULL; 17376259Sgreen 17476259Sgreen old = *s; 17576259Sgreen 176162852Sdes *s = strpbrk(*s, WHITESPACE QUOTE "="); 17776259Sgreen if (*s == NULL) 17876259Sgreen return (old); 17976259Sgreen 180162852Sdes if (*s[0] == '\"') { 181162852Sdes memmove(*s, *s + 1, strlen(*s)); /* move nul too */ 182162852Sdes /* Find matching quote */ 183162852Sdes if ((*s = strpbrk(*s, QUOTE)) == NULL) { 184162852Sdes return (NULL); /* no matching quote */ 185162852Sdes } else { 186162852Sdes *s[0] = '\0'; 187215116Sdes *s += strspn(*s + 1, WHITESPACE) + 1; 188162852Sdes return (old); 189162852Sdes } 190162852Sdes } 191162852Sdes 19276259Sgreen /* Allow only one '=' to be skipped */ 19376259Sgreen if (*s[0] == '=') 19476259Sgreen wspace = 1; 19576259Sgreen *s[0] = '\0'; 19676259Sgreen 197162852Sdes /* Skip any extra whitespace after first token */ 19876259Sgreen *s += strspn(*s + 1, WHITESPACE) + 1; 19976259Sgreen if (*s[0] == '=' && !wspace) 20076259Sgreen *s += strspn(*s + 1, WHITESPACE) + 1; 20176259Sgreen 20276259Sgreen return (old); 20376259Sgreen} 20476259Sgreen 20576259Sgreenstruct passwd * 20676259Sgreenpwcopy(struct passwd *pw) 20776259Sgreen{ 208162852Sdes struct passwd *copy = xcalloc(1, sizeof(*copy)); 20976259Sgreen 21076259Sgreen copy->pw_name = xstrdup(pw->pw_name); 21176259Sgreen copy->pw_passwd = xstrdup(pw->pw_passwd); 212255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_GECOS 21376259Sgreen copy->pw_gecos = xstrdup(pw->pw_gecos); 214255767Sdes#endif 21576259Sgreen copy->pw_uid = pw->pw_uid; 21676259Sgreen copy->pw_gid = pw->pw_gid; 217255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE 21892555Sdes copy->pw_expire = pw->pw_expire; 21998937Sdes#endif 220255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CHANGE 22192555Sdes copy->pw_change = pw->pw_change; 22298937Sdes#endif 223255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CLASS 22476259Sgreen copy->pw_class = xstrdup(pw->pw_class); 22598937Sdes#endif 22676259Sgreen copy->pw_dir = xstrdup(pw->pw_dir); 22776259Sgreen copy->pw_shell = xstrdup(pw->pw_shell); 22876259Sgreen return copy; 22976259Sgreen} 23076259Sgreen 23192555Sdes/* 23292555Sdes * Convert ASCII string to TCP/IP port number. 233192595Sdes * Port must be >=0 and <=65535. 234192595Sdes * Return -1 if invalid. 23592555Sdes */ 23692555Sdesint 23792555Sdesa2port(const char *s) 23876259Sgreen{ 239192595Sdes long long port; 240192595Sdes const char *errstr; 24176259Sgreen 242192595Sdes port = strtonum(s, 0, 65535, &errstr); 243192595Sdes if (errstr != NULL) 244192595Sdes return -1; 245192595Sdes return (int)port; 24676259Sgreen} 24792555Sdes 248157016Sdesint 249157016Sdesa2tun(const char *s, int *remote) 250157016Sdes{ 251157016Sdes const char *errstr = NULL; 252157016Sdes char *sp, *ep; 253157016Sdes int tun; 254157016Sdes 255157016Sdes if (remote != NULL) { 256157016Sdes *remote = SSH_TUNID_ANY; 257157016Sdes sp = xstrdup(s); 258157016Sdes if ((ep = strchr(sp, ':')) == NULL) { 259255767Sdes free(sp); 260157016Sdes return (a2tun(s, NULL)); 261157016Sdes } 262157016Sdes ep[0] = '\0'; ep++; 263157016Sdes *remote = a2tun(ep, NULL); 264157016Sdes tun = a2tun(sp, NULL); 265255767Sdes free(sp); 266157016Sdes return (*remote == SSH_TUNID_ERR ? *remote : tun); 267157016Sdes } 268157016Sdes 269157016Sdes if (strcasecmp(s, "any") == 0) 270157016Sdes return (SSH_TUNID_ANY); 271157016Sdes 272157016Sdes tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); 273157016Sdes if (errstr != NULL) 274157016Sdes return (SSH_TUNID_ERR); 275157016Sdes 276157016Sdes return (tun); 277157016Sdes} 278157016Sdes 27992555Sdes#define SECONDS 1 28092555Sdes#define MINUTES (SECONDS * 60) 28192555Sdes#define HOURS (MINUTES * 60) 28292555Sdes#define DAYS (HOURS * 24) 28392555Sdes#define WEEKS (DAYS * 7) 28492555Sdes 28592555Sdes/* 28692555Sdes * Convert a time string into seconds; format is 28792555Sdes * a sequence of: 28892555Sdes * time[qualifier] 28992555Sdes * 29092555Sdes * Valid time qualifiers are: 29192555Sdes * <none> seconds 29292555Sdes * s|S seconds 29392555Sdes * m|M minutes 29492555Sdes * h|H hours 29592555Sdes * d|D days 29692555Sdes * w|W weeks 29792555Sdes * 29892555Sdes * Examples: 29992555Sdes * 90m 90 minutes 30092555Sdes * 1h30m 90 minutes 30192555Sdes * 2d 2 days 30292555Sdes * 1w 1 week 30392555Sdes * 30492555Sdes * Return -1 if time string is invalid. 30592555Sdes */ 30692555Sdeslong 30792555Sdesconvtime(const char *s) 30892555Sdes{ 30992555Sdes long total, secs; 31092555Sdes const char *p; 31192555Sdes char *endp; 31292555Sdes 31392555Sdes errno = 0; 31492555Sdes total = 0; 31592555Sdes p = s; 31692555Sdes 31792555Sdes if (p == NULL || *p == '\0') 31892555Sdes return -1; 31992555Sdes 32092555Sdes while (*p) { 32192555Sdes secs = strtol(p, &endp, 10); 32292555Sdes if (p == endp || 32392555Sdes (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 32492555Sdes secs < 0) 32592555Sdes return -1; 32692555Sdes 32792555Sdes switch (*endp++) { 32892555Sdes case '\0': 32992555Sdes endp--; 330162852Sdes break; 33192555Sdes case 's': 33292555Sdes case 'S': 33392555Sdes break; 33492555Sdes case 'm': 33592555Sdes case 'M': 33692555Sdes secs *= MINUTES; 33792555Sdes break; 33892555Sdes case 'h': 33992555Sdes case 'H': 34092555Sdes secs *= HOURS; 34192555Sdes break; 34292555Sdes case 'd': 34392555Sdes case 'D': 34492555Sdes secs *= DAYS; 34592555Sdes break; 34692555Sdes case 'w': 34792555Sdes case 'W': 34892555Sdes secs *= WEEKS; 34992555Sdes break; 35092555Sdes default: 35192555Sdes return -1; 35292555Sdes } 35392555Sdes total += secs; 35492555Sdes if (total < 0) 35592555Sdes return -1; 35692555Sdes p = endp; 35792555Sdes } 35892555Sdes 35992555Sdes return total; 36092555Sdes} 36192555Sdes 362146998Sdes/* 363162852Sdes * Returns a standardized host+port identifier string. 364162852Sdes * Caller must free returned string. 365162852Sdes */ 366162852Sdeschar * 367162852Sdesput_host_port(const char *host, u_short port) 368162852Sdes{ 369162852Sdes char *hoststr; 370162852Sdes 371162852Sdes if (port == 0 || port == SSH_DEFAULT_PORT) 372162852Sdes return(xstrdup(host)); 373162852Sdes if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) 374162852Sdes fatal("put_host_port: asprintf: %s", strerror(errno)); 375162852Sdes debug3("put_host_port: %s", hoststr); 376162852Sdes return hoststr; 377162852Sdes} 378162852Sdes 379162852Sdes/* 380146998Sdes * Search for next delimiter between hostnames/addresses and ports. 381146998Sdes * Argument may be modified (for termination). 382146998Sdes * Returns *cp if parsing succeeds. 383146998Sdes * *cp is set to the start of the next delimiter, if one was found. 384146998Sdes * If this is the last field, *cp is set to NULL. 385146998Sdes */ 38692555Sdeschar * 387146998Sdeshpdelim(char **cp) 388146998Sdes{ 389146998Sdes char *s, *old; 390146998Sdes 391146998Sdes if (cp == NULL || *cp == NULL) 392146998Sdes return NULL; 393146998Sdes 394146998Sdes old = s = *cp; 395146998Sdes if (*s == '[') { 396146998Sdes if ((s = strchr(s, ']')) == NULL) 397146998Sdes return NULL; 398146998Sdes else 399146998Sdes s++; 400146998Sdes } else if ((s = strpbrk(s, ":/")) == NULL) 401146998Sdes s = *cp + strlen(*cp); /* skip to end (see first case below) */ 402146998Sdes 403146998Sdes switch (*s) { 404146998Sdes case '\0': 405146998Sdes *cp = NULL; /* no more fields*/ 406146998Sdes break; 407147001Sdes 408146998Sdes case ':': 409146998Sdes case '/': 410146998Sdes *s = '\0'; /* terminate */ 411146998Sdes *cp = s + 1; 412146998Sdes break; 413147001Sdes 414146998Sdes default: 415146998Sdes return NULL; 416146998Sdes } 417146998Sdes 418146998Sdes return old; 419146998Sdes} 420146998Sdes 421146998Sdeschar * 42292555Sdescleanhostname(char *host) 42392555Sdes{ 42492555Sdes if (*host == '[' && host[strlen(host) - 1] == ']') { 42592555Sdes host[strlen(host) - 1] = '\0'; 42692555Sdes return (host + 1); 42792555Sdes } else 42892555Sdes return host; 42992555Sdes} 43092555Sdes 43192555Sdeschar * 43292555Sdescolon(char *cp) 43392555Sdes{ 43492555Sdes int flag = 0; 43592555Sdes 43692555Sdes if (*cp == ':') /* Leading colon is part of file name. */ 437215116Sdes return NULL; 43892555Sdes if (*cp == '[') 43992555Sdes flag = 1; 44092555Sdes 44192555Sdes for (; *cp; ++cp) { 44292555Sdes if (*cp == '@' && *(cp+1) == '[') 44392555Sdes flag = 1; 44492555Sdes if (*cp == ']' && *(cp+1) == ':' && flag) 44592555Sdes return (cp+1); 44692555Sdes if (*cp == ':' && !flag) 44792555Sdes return (cp); 44892555Sdes if (*cp == '/') 449215116Sdes return NULL; 45092555Sdes } 451215116Sdes return NULL; 45292555Sdes} 45392555Sdes 454323124Sdes/* 455323124Sdes * Parse a [user@]host[:port] string. 456323124Sdes * Caller must free returned user and host. 457323124Sdes * Any of the pointer return arguments may be NULL (useful for syntax checking). 458323124Sdes * If user was not specified then *userp will be set to NULL. 459323124Sdes * If port was not specified then *portp will be -1. 460323124Sdes * Returns 0 on success, -1 on failure. 461323124Sdes */ 462323124Sdesint 463323124Sdesparse_user_host_port(const char *s, char **userp, char **hostp, int *portp) 464323124Sdes{ 465323124Sdes char *sdup, *cp, *tmp; 466323124Sdes char *user = NULL, *host = NULL; 467323124Sdes int port = -1, ret = -1; 468323124Sdes 469323124Sdes if (userp != NULL) 470323124Sdes *userp = NULL; 471323124Sdes if (hostp != NULL) 472323124Sdes *hostp = NULL; 473323124Sdes if (portp != NULL) 474323124Sdes *portp = -1; 475323124Sdes 476323124Sdes if ((sdup = tmp = strdup(s)) == NULL) 477323124Sdes return -1; 478323124Sdes /* Extract optional username */ 479323124Sdes if ((cp = strchr(tmp, '@')) != NULL) { 480323124Sdes *cp = '\0'; 481323124Sdes if (*tmp == '\0') 482323124Sdes goto out; 483323124Sdes if ((user = strdup(tmp)) == NULL) 484323124Sdes goto out; 485323124Sdes tmp = cp + 1; 486323124Sdes } 487323124Sdes /* Extract mandatory hostname */ 488323124Sdes if ((cp = hpdelim(&tmp)) == NULL || *cp == '\0') 489323124Sdes goto out; 490323124Sdes host = xstrdup(cleanhostname(cp)); 491323124Sdes /* Convert and verify optional port */ 492323124Sdes if (tmp != NULL && *tmp != '\0') { 493323124Sdes if ((port = a2port(tmp)) <= 0) 494323124Sdes goto out; 495323124Sdes } 496323124Sdes /* Success */ 497323124Sdes if (userp != NULL) { 498323124Sdes *userp = user; 499323124Sdes user = NULL; 500323124Sdes } 501323124Sdes if (hostp != NULL) { 502323124Sdes *hostp = host; 503323124Sdes host = NULL; 504323124Sdes } 505323124Sdes if (portp != NULL) 506323124Sdes *portp = port; 507323124Sdes ret = 0; 508323124Sdes out: 509323124Sdes free(sdup); 510323124Sdes free(user); 511323124Sdes free(host); 512323124Sdes return ret; 513323124Sdes} 514323124Sdes 51592555Sdes/* function to assist building execv() arguments */ 51692555Sdesvoid 51792555Sdesaddargs(arglist *args, char *fmt, ...) 51892555Sdes{ 51992555Sdes va_list ap; 520157016Sdes char *cp; 521137015Sdes u_int nalloc; 522157016Sdes int r; 52392555Sdes 52492555Sdes va_start(ap, fmt); 525157016Sdes r = vasprintf(&cp, fmt, ap); 52692555Sdes va_end(ap); 527157016Sdes if (r == -1) 528157016Sdes fatal("addargs: argument too long"); 52992555Sdes 530120161Snectar nalloc = args->nalloc; 53192555Sdes if (args->list == NULL) { 532120161Snectar nalloc = 32; 53392555Sdes args->num = 0; 534120161Snectar } else if (args->num+2 >= nalloc) 535120161Snectar nalloc *= 2; 53692555Sdes 537295367Sdes args->list = xreallocarray(args->list, nalloc, sizeof(char *)); 538120161Snectar args->nalloc = nalloc; 539157016Sdes args->list[args->num++] = cp; 54092555Sdes args->list[args->num] = NULL; 54192555Sdes} 542146998Sdes 543157016Sdesvoid 544157016Sdesreplacearg(arglist *args, u_int which, char *fmt, ...) 545157016Sdes{ 546157016Sdes va_list ap; 547157016Sdes char *cp; 548157016Sdes int r; 549157016Sdes 550157016Sdes va_start(ap, fmt); 551157016Sdes r = vasprintf(&cp, fmt, ap); 552157016Sdes va_end(ap); 553157016Sdes if (r == -1) 554157016Sdes fatal("replacearg: argument too long"); 555157016Sdes 556157016Sdes if (which >= args->num) 557157016Sdes fatal("replacearg: tried to replace invalid arg %d >= %d", 558157016Sdes which, args->num); 559255767Sdes free(args->list[which]); 560157016Sdes args->list[which] = cp; 561157016Sdes} 562157016Sdes 563157016Sdesvoid 564157016Sdesfreeargs(arglist *args) 565157016Sdes{ 566157016Sdes u_int i; 567157016Sdes 568157016Sdes if (args->list != NULL) { 569157016Sdes for (i = 0; i < args->num; i++) 570255767Sdes free(args->list[i]); 571255767Sdes free(args->list); 572157016Sdes args->nalloc = args->num = 0; 573157016Sdes args->list = NULL; 574157016Sdes } 575157016Sdes} 576157016Sdes 577146998Sdes/* 578149749Sdes * Expands tildes in the file name. Returns data allocated by xmalloc. 579149749Sdes * Warning: this calls getpw*. 580149749Sdes */ 581149749Sdeschar * 582149749Sdestilde_expand_filename(const char *filename, uid_t uid) 583149749Sdes{ 584255767Sdes const char *path, *sep; 585255767Sdes char user[128], *ret; 586149749Sdes struct passwd *pw; 587149749Sdes u_int len, slash; 588149749Sdes 589149749Sdes if (*filename != '~') 590149749Sdes return (xstrdup(filename)); 591149749Sdes filename++; 592149749Sdes 593149749Sdes path = strchr(filename, '/'); 594149749Sdes if (path != NULL && path > filename) { /* ~user/path */ 595149749Sdes slash = path - filename; 596149749Sdes if (slash > sizeof(user) - 1) 597149749Sdes fatal("tilde_expand_filename: ~username too long"); 598149749Sdes memcpy(user, filename, slash); 599149749Sdes user[slash] = '\0'; 600149749Sdes if ((pw = getpwnam(user)) == NULL) 601149749Sdes fatal("tilde_expand_filename: No such user %s", user); 602149749Sdes } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ 603181111Sdes fatal("tilde_expand_filename: No such uid %ld", (long)uid); 604149749Sdes 605149749Sdes /* Make sure directory has a trailing '/' */ 606149749Sdes len = strlen(pw->pw_dir); 607255767Sdes if (len == 0 || pw->pw_dir[len - 1] != '/') 608255767Sdes sep = "/"; 609255767Sdes else 610255767Sdes sep = ""; 611149749Sdes 612149749Sdes /* Skip leading '/' from specified path */ 613149749Sdes if (path != NULL) 614149749Sdes filename = path + 1; 615255767Sdes 616295367Sdes if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX) 617149749Sdes fatal("tilde_expand_filename: Path too long"); 618149749Sdes 619255767Sdes return (ret); 620149749Sdes} 621149749Sdes 622149749Sdes/* 623149749Sdes * Expand a string with a set of %[char] escapes. A number of escapes may be 624149749Sdes * specified as (char *escape_chars, char *replacement) pairs. The list must 625149749Sdes * be terminated by a NULL escape_char. Returns replaced string in memory 626149749Sdes * allocated by xmalloc. 627149749Sdes */ 628149749Sdeschar * 629149749Sdespercent_expand(const char *string, ...) 630149749Sdes{ 631149749Sdes#define EXPAND_MAX_KEYS 16 632204917Sdes u_int num_keys, i, j; 633149749Sdes struct { 634149749Sdes const char *key; 635149749Sdes const char *repl; 636149749Sdes } keys[EXPAND_MAX_KEYS]; 637149749Sdes char buf[4096]; 638149749Sdes va_list ap; 639149749Sdes 640149749Sdes /* Gather keys */ 641149749Sdes va_start(ap, string); 642149749Sdes for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 643149749Sdes keys[num_keys].key = va_arg(ap, char *); 644149749Sdes if (keys[num_keys].key == NULL) 645149749Sdes break; 646149749Sdes keys[num_keys].repl = va_arg(ap, char *); 647149749Sdes if (keys[num_keys].repl == NULL) 648204917Sdes fatal("%s: NULL replacement", __func__); 649149749Sdes } 650204917Sdes if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) 651204917Sdes fatal("%s: too many keys", __func__); 652149749Sdes va_end(ap); 653149749Sdes 654149749Sdes /* Expand string */ 655149749Sdes *buf = '\0'; 656149749Sdes for (i = 0; *string != '\0'; string++) { 657149749Sdes if (*string != '%') { 658149749Sdes append: 659149749Sdes buf[i++] = *string; 660149749Sdes if (i >= sizeof(buf)) 661204917Sdes fatal("%s: string too long", __func__); 662149749Sdes buf[i] = '\0'; 663149749Sdes continue; 664149749Sdes } 665149749Sdes string++; 666204917Sdes /* %% case */ 667149749Sdes if (*string == '%') 668149749Sdes goto append; 669296781Sdes if (*string == '\0') 670296781Sdes fatal("%s: invalid format", __func__); 671149749Sdes for (j = 0; j < num_keys; j++) { 672149749Sdes if (strchr(keys[j].key, *string) != NULL) { 673149749Sdes i = strlcat(buf, keys[j].repl, sizeof(buf)); 674149749Sdes if (i >= sizeof(buf)) 675204917Sdes fatal("%s: string too long", __func__); 676149749Sdes break; 677149749Sdes } 678149749Sdes } 679149749Sdes if (j >= num_keys) 680204917Sdes fatal("%s: unknown key %%%c", __func__, *string); 681149749Sdes } 682149749Sdes return (xstrdup(buf)); 683149749Sdes#undef EXPAND_MAX_KEYS 684149749Sdes} 685149749Sdes 686149749Sdes/* 687146998Sdes * Read an entire line from a public key file into a static buffer, discarding 688146998Sdes * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 689146998Sdes */ 690146998Sdesint 691146998Sdesread_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 692146998Sdes u_long *lineno) 693146998Sdes{ 694146998Sdes while (fgets(buf, bufsz, f) != NULL) { 695181111Sdes if (buf[0] == '\0') 696181111Sdes continue; 697146998Sdes (*lineno)++; 698146998Sdes if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 699146998Sdes return 0; 700146998Sdes } else { 701146998Sdes debug("%s: %s line %lu exceeds size limit", __func__, 702146998Sdes filename, *lineno); 703146998Sdes /* discard remainder of line */ 704147001Sdes while (fgetc(f) != '\n' && !feof(f)) 705146998Sdes ; /* nothing */ 706146998Sdes } 707146998Sdes } 708146998Sdes return -1; 709146998Sdes} 710149749Sdes 711157016Sdesint 712157016Sdestun_open(int tun, int mode) 713157016Sdes{ 714157016Sdes#if defined(CUSTOM_SYS_TUN_OPEN) 715157016Sdes return (sys_tun_open(tun, mode)); 716157016Sdes#elif defined(SSH_TUN_OPENBSD) 717157016Sdes struct ifreq ifr; 718157016Sdes char name[100]; 719157016Sdes int fd = -1, sock; 720296781Sdes const char *tunbase = "tun"; 721157016Sdes 722296781Sdes if (mode == SSH_TUNMODE_ETHERNET) 723296781Sdes tunbase = "tap"; 724296781Sdes 725157016Sdes /* Open the tunnel device */ 726157016Sdes if (tun <= SSH_TUNID_MAX) { 727296781Sdes snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun); 728157016Sdes fd = open(name, O_RDWR); 729157016Sdes } else if (tun == SSH_TUNID_ANY) { 730157016Sdes for (tun = 100; tun >= 0; tun--) { 731296781Sdes snprintf(name, sizeof(name), "/dev/%s%d", 732296781Sdes tunbase, tun); 733157016Sdes if ((fd = open(name, O_RDWR)) >= 0) 734157016Sdes break; 735157016Sdes } 736157016Sdes } else { 737157016Sdes debug("%s: invalid tunnel %u", __func__, tun); 738296781Sdes return -1; 739157016Sdes } 740157016Sdes 741157016Sdes if (fd < 0) { 742296781Sdes debug("%s: %s open: %s", __func__, name, strerror(errno)); 743296781Sdes return -1; 744157016Sdes } 745157016Sdes 746157016Sdes debug("%s: %s mode %d fd %d", __func__, name, mode, fd); 747157016Sdes 748296781Sdes /* Bring interface up if it is not already */ 749296781Sdes snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); 750157016Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 751157016Sdes goto failed; 752157016Sdes 753296781Sdes if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { 754296781Sdes debug("%s: get interface %s flags: %s", __func__, 755296781Sdes ifr.ifr_name, strerror(errno)); 756157016Sdes goto failed; 757296781Sdes } 758157016Sdes 759296781Sdes if (!(ifr.ifr_flags & IFF_UP)) { 760296781Sdes ifr.ifr_flags |= IFF_UP; 761296781Sdes if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { 762296781Sdes debug("%s: activate interface %s: %s", __func__, 763296781Sdes ifr.ifr_name, strerror(errno)); 764296781Sdes goto failed; 765296781Sdes } 766296781Sdes } 767157016Sdes 768157016Sdes close(sock); 769296781Sdes return fd; 770157016Sdes 771157016Sdes failed: 772157016Sdes if (fd >= 0) 773157016Sdes close(fd); 774157016Sdes if (sock >= 0) 775157016Sdes close(sock); 776296781Sdes return -1; 777157016Sdes#else 778157016Sdes error("Tunnel interfaces are not supported on this platform"); 779157016Sdes return (-1); 780157016Sdes#endif 781157016Sdes} 782157016Sdes 783157016Sdesvoid 784157016Sdessanitise_stdfd(void) 785157016Sdes{ 786157016Sdes int nullfd, dupfd; 787157016Sdes 788157016Sdes if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 789192595Sdes fprintf(stderr, "Couldn't open /dev/null: %s\n", 790192595Sdes strerror(errno)); 791157016Sdes exit(1); 792157016Sdes } 793323124Sdes while (++dupfd <= STDERR_FILENO) { 794323124Sdes /* Only populate closed fds. */ 795323124Sdes if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) { 796323124Sdes if (dup2(nullfd, dupfd) == -1) { 797323124Sdes fprintf(stderr, "dup2: %s\n", strerror(errno)); 798323124Sdes exit(1); 799323124Sdes } 800157016Sdes } 801157016Sdes } 802323124Sdes if (nullfd > STDERR_FILENO) 803157016Sdes close(nullfd); 804157016Sdes} 805157016Sdes 806149749Sdeschar * 807162852Sdestohex(const void *vp, size_t l) 808149749Sdes{ 809162852Sdes const u_char *p = (const u_char *)vp; 810149749Sdes char b[3], *r; 811162852Sdes size_t i, hl; 812149749Sdes 813162852Sdes if (l > 65536) 814162852Sdes return xstrdup("tohex: length > 65536"); 815162852Sdes 816149749Sdes hl = l * 2 + 1; 817162852Sdes r = xcalloc(1, hl); 818149749Sdes for (i = 0; i < l; i++) { 819162852Sdes snprintf(b, sizeof(b), "%02x", p[i]); 820149749Sdes strlcat(r, b, hl); 821149749Sdes } 822149749Sdes return (r); 823149749Sdes} 824149749Sdes 825162852Sdesu_int64_t 826162852Sdesget_u64(const void *vp) 827162852Sdes{ 828162852Sdes const u_char *p = (const u_char *)vp; 829162852Sdes u_int64_t v; 830162852Sdes 831162852Sdes v = (u_int64_t)p[0] << 56; 832162852Sdes v |= (u_int64_t)p[1] << 48; 833162852Sdes v |= (u_int64_t)p[2] << 40; 834162852Sdes v |= (u_int64_t)p[3] << 32; 835162852Sdes v |= (u_int64_t)p[4] << 24; 836162852Sdes v |= (u_int64_t)p[5] << 16; 837162852Sdes v |= (u_int64_t)p[6] << 8; 838162852Sdes v |= (u_int64_t)p[7]; 839162852Sdes 840162852Sdes return (v); 841162852Sdes} 842162852Sdes 843162852Sdesu_int32_t 844162852Sdesget_u32(const void *vp) 845162852Sdes{ 846162852Sdes const u_char *p = (const u_char *)vp; 847162852Sdes u_int32_t v; 848162852Sdes 849162852Sdes v = (u_int32_t)p[0] << 24; 850162852Sdes v |= (u_int32_t)p[1] << 16; 851162852Sdes v |= (u_int32_t)p[2] << 8; 852162852Sdes v |= (u_int32_t)p[3]; 853162852Sdes 854162852Sdes return (v); 855162852Sdes} 856162852Sdes 857295367Sdesu_int32_t 858295367Sdesget_u32_le(const void *vp) 859295367Sdes{ 860295367Sdes const u_char *p = (const u_char *)vp; 861295367Sdes u_int32_t v; 862295367Sdes 863295367Sdes v = (u_int32_t)p[0]; 864295367Sdes v |= (u_int32_t)p[1] << 8; 865295367Sdes v |= (u_int32_t)p[2] << 16; 866295367Sdes v |= (u_int32_t)p[3] << 24; 867295367Sdes 868295367Sdes return (v); 869295367Sdes} 870295367Sdes 871162852Sdesu_int16_t 872162852Sdesget_u16(const void *vp) 873162852Sdes{ 874162852Sdes const u_char *p = (const u_char *)vp; 875162852Sdes u_int16_t v; 876162852Sdes 877162852Sdes v = (u_int16_t)p[0] << 8; 878162852Sdes v |= (u_int16_t)p[1]; 879162852Sdes 880162852Sdes return (v); 881162852Sdes} 882162852Sdes 883162852Sdesvoid 884162852Sdesput_u64(void *vp, u_int64_t v) 885162852Sdes{ 886162852Sdes u_char *p = (u_char *)vp; 887162852Sdes 888162852Sdes p[0] = (u_char)(v >> 56) & 0xff; 889162852Sdes p[1] = (u_char)(v >> 48) & 0xff; 890162852Sdes p[2] = (u_char)(v >> 40) & 0xff; 891162852Sdes p[3] = (u_char)(v >> 32) & 0xff; 892162852Sdes p[4] = (u_char)(v >> 24) & 0xff; 893162852Sdes p[5] = (u_char)(v >> 16) & 0xff; 894162852Sdes p[6] = (u_char)(v >> 8) & 0xff; 895162852Sdes p[7] = (u_char)v & 0xff; 896162852Sdes} 897162852Sdes 898162852Sdesvoid 899162852Sdesput_u32(void *vp, u_int32_t v) 900162852Sdes{ 901162852Sdes u_char *p = (u_char *)vp; 902162852Sdes 903162852Sdes p[0] = (u_char)(v >> 24) & 0xff; 904162852Sdes p[1] = (u_char)(v >> 16) & 0xff; 905162852Sdes p[2] = (u_char)(v >> 8) & 0xff; 906162852Sdes p[3] = (u_char)v & 0xff; 907162852Sdes} 908162852Sdes 909295367Sdesvoid 910295367Sdesput_u32_le(void *vp, u_int32_t v) 911295367Sdes{ 912295367Sdes u_char *p = (u_char *)vp; 913162852Sdes 914295367Sdes p[0] = (u_char)v & 0xff; 915295367Sdes p[1] = (u_char)(v >> 8) & 0xff; 916295367Sdes p[2] = (u_char)(v >> 16) & 0xff; 917295367Sdes p[3] = (u_char)(v >> 24) & 0xff; 918295367Sdes} 919295367Sdes 920162852Sdesvoid 921162852Sdesput_u16(void *vp, u_int16_t v) 922162852Sdes{ 923162852Sdes u_char *p = (u_char *)vp; 924162852Sdes 925162852Sdes p[0] = (u_char)(v >> 8) & 0xff; 926162852Sdes p[1] = (u_char)v & 0xff; 927162852Sdes} 928181111Sdes 929181111Sdesvoid 930181111Sdesms_subtract_diff(struct timeval *start, int *ms) 931181111Sdes{ 932181111Sdes struct timeval diff, finish; 933181111Sdes 934181111Sdes gettimeofday(&finish, NULL); 935181111Sdes timersub(&finish, start, &diff); 936181111Sdes *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); 937181111Sdes} 938181111Sdes 939181111Sdesvoid 940181111Sdesms_to_timeval(struct timeval *tv, int ms) 941181111Sdes{ 942181111Sdes if (ms < 0) 943181111Sdes ms = 0; 944181111Sdes tv->tv_sec = ms / 1000; 945181111Sdes tv->tv_usec = (ms % 1000) * 1000; 946181111Sdes} 947181111Sdes 948255767Sdestime_t 949255767Sdesmonotime(void) 950255767Sdes{ 951295367Sdes#if defined(HAVE_CLOCK_GETTIME) && \ 952295367Sdes (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME)) 953255767Sdes struct timespec ts; 954255767Sdes static int gettime_failed = 0; 955255767Sdes 956255767Sdes if (!gettime_failed) { 957295367Sdes#if defined(CLOCK_BOOTTIME) 958295367Sdes if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) 959295367Sdes return (ts.tv_sec); 960295367Sdes#endif 961295367Sdes#if defined(CLOCK_MONOTONIC) 962255767Sdes if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) 963255767Sdes return (ts.tv_sec); 964295367Sdes#endif 965255767Sdes debug3("clock_gettime: %s", strerror(errno)); 966255767Sdes gettime_failed = 1; 967255767Sdes } 968295367Sdes#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */ 969255767Sdes 970255767Sdes return time(NULL); 971255767Sdes} 972255767Sdes 973323124Sdesdouble 974323124Sdesmonotime_double(void) 975323124Sdes{ 976323124Sdes#if defined(HAVE_CLOCK_GETTIME) && \ 977323124Sdes (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME)) 978323124Sdes struct timespec ts; 979323124Sdes static int gettime_failed = 0; 980323124Sdes 981323124Sdes if (!gettime_failed) { 982323124Sdes#if defined(CLOCK_BOOTTIME) 983323124Sdes if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) 984323124Sdes return (ts.tv_sec + (double)ts.tv_nsec / 1000000000); 985323124Sdes#endif 986323124Sdes#if defined(CLOCK_MONOTONIC) 987323124Sdes if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) 988323124Sdes return (ts.tv_sec + (double)ts.tv_nsec / 1000000000); 989323124Sdes#endif 990323124Sdes debug3("clock_gettime: %s", strerror(errno)); 991323124Sdes gettime_failed = 1; 992323124Sdes } 993323124Sdes#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */ 994323124Sdes 995323124Sdes return (double)time(NULL); 996323124Sdes} 997323124Sdes 998221420Sdesvoid 999221420Sdesbandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen) 1000221420Sdes{ 1001221420Sdes bw->buflen = buflen; 1002221420Sdes bw->rate = kbps; 1003221420Sdes bw->thresh = bw->rate; 1004221420Sdes bw->lamt = 0; 1005221420Sdes timerclear(&bw->bwstart); 1006221420Sdes timerclear(&bw->bwend); 1007221420Sdes} 1008221420Sdes 1009221420Sdes/* Callback from read/write loop to insert bandwidth-limiting delays */ 1010221420Sdesvoid 1011221420Sdesbandwidth_limit(struct bwlimit *bw, size_t read_len) 1012221420Sdes{ 1013221420Sdes u_int64_t waitlen; 1014221420Sdes struct timespec ts, rm; 1015221420Sdes 1016221420Sdes if (!timerisset(&bw->bwstart)) { 1017221420Sdes gettimeofday(&bw->bwstart, NULL); 1018221420Sdes return; 1019221420Sdes } 1020221420Sdes 1021221420Sdes bw->lamt += read_len; 1022221420Sdes if (bw->lamt < bw->thresh) 1023221420Sdes return; 1024221420Sdes 1025221420Sdes gettimeofday(&bw->bwend, NULL); 1026221420Sdes timersub(&bw->bwend, &bw->bwstart, &bw->bwend); 1027221420Sdes if (!timerisset(&bw->bwend)) 1028221420Sdes return; 1029221420Sdes 1030221420Sdes bw->lamt *= 8; 1031221420Sdes waitlen = (double)1000000L * bw->lamt / bw->rate; 1032221420Sdes 1033221420Sdes bw->bwstart.tv_sec = waitlen / 1000000L; 1034221420Sdes bw->bwstart.tv_usec = waitlen % 1000000L; 1035221420Sdes 1036221420Sdes if (timercmp(&bw->bwstart, &bw->bwend, >)) { 1037221420Sdes timersub(&bw->bwstart, &bw->bwend, &bw->bwend); 1038221420Sdes 1039221420Sdes /* Adjust the wait time */ 1040221420Sdes if (bw->bwend.tv_sec) { 1041221420Sdes bw->thresh /= 2; 1042221420Sdes if (bw->thresh < bw->buflen / 4) 1043221420Sdes bw->thresh = bw->buflen / 4; 1044221420Sdes } else if (bw->bwend.tv_usec < 10000) { 1045221420Sdes bw->thresh *= 2; 1046221420Sdes if (bw->thresh > bw->buflen * 8) 1047221420Sdes bw->thresh = bw->buflen * 8; 1048221420Sdes } 1049221420Sdes 1050221420Sdes TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts); 1051221420Sdes while (nanosleep(&ts, &rm) == -1) { 1052221420Sdes if (errno != EINTR) 1053221420Sdes break; 1054221420Sdes ts = rm; 1055221420Sdes } 1056221420Sdes } 1057221420Sdes 1058221420Sdes bw->lamt = 0; 1059221420Sdes gettimeofday(&bw->bwstart, NULL); 1060221420Sdes} 1061221420Sdes 1062221420Sdes/* Make a template filename for mk[sd]temp() */ 1063221420Sdesvoid 1064221420Sdesmktemp_proto(char *s, size_t len) 1065221420Sdes{ 1066221420Sdes const char *tmpdir; 1067221420Sdes int r; 1068221420Sdes 1069221420Sdes if ((tmpdir = getenv("TMPDIR")) != NULL) { 1070221420Sdes r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir); 1071221420Sdes if (r > 0 && (size_t)r < len) 1072221420Sdes return; 1073221420Sdes } 1074221420Sdes r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); 1075221420Sdes if (r < 0 || (size_t)r >= len) 1076221420Sdes fatal("%s: template string too short", __func__); 1077221420Sdes} 1078221420Sdes 1079221420Sdesstatic const struct { 1080221420Sdes const char *name; 1081221420Sdes int value; 1082221420Sdes} ipqos[] = { 1083221420Sdes { "af11", IPTOS_DSCP_AF11 }, 1084221420Sdes { "af12", IPTOS_DSCP_AF12 }, 1085221420Sdes { "af13", IPTOS_DSCP_AF13 }, 1086240075Sdes { "af21", IPTOS_DSCP_AF21 }, 1087221420Sdes { "af22", IPTOS_DSCP_AF22 }, 1088221420Sdes { "af23", IPTOS_DSCP_AF23 }, 1089221420Sdes { "af31", IPTOS_DSCP_AF31 }, 1090221420Sdes { "af32", IPTOS_DSCP_AF32 }, 1091221420Sdes { "af33", IPTOS_DSCP_AF33 }, 1092221420Sdes { "af41", IPTOS_DSCP_AF41 }, 1093221420Sdes { "af42", IPTOS_DSCP_AF42 }, 1094221420Sdes { "af43", IPTOS_DSCP_AF43 }, 1095221420Sdes { "cs0", IPTOS_DSCP_CS0 }, 1096221420Sdes { "cs1", IPTOS_DSCP_CS1 }, 1097221420Sdes { "cs2", IPTOS_DSCP_CS2 }, 1098221420Sdes { "cs3", IPTOS_DSCP_CS3 }, 1099221420Sdes { "cs4", IPTOS_DSCP_CS4 }, 1100221420Sdes { "cs5", IPTOS_DSCP_CS5 }, 1101221420Sdes { "cs6", IPTOS_DSCP_CS6 }, 1102221420Sdes { "cs7", IPTOS_DSCP_CS7 }, 1103221420Sdes { "ef", IPTOS_DSCP_EF }, 1104221420Sdes { "lowdelay", IPTOS_LOWDELAY }, 1105221420Sdes { "throughput", IPTOS_THROUGHPUT }, 1106221420Sdes { "reliability", IPTOS_RELIABILITY }, 1107221420Sdes { NULL, -1 } 1108221420Sdes}; 1109221420Sdes 1110215116Sdesint 1111221420Sdesparse_ipqos(const char *cp) 1112215116Sdes{ 1113221420Sdes u_int i; 1114221420Sdes char *ep; 1115221420Sdes long val; 1116215116Sdes 1117221420Sdes if (cp == NULL) 1118221420Sdes return -1; 1119221420Sdes for (i = 0; ipqos[i].name != NULL; i++) { 1120221420Sdes if (strcasecmp(cp, ipqos[i].name) == 0) 1121221420Sdes return ipqos[i].value; 1122221420Sdes } 1123221420Sdes /* Try parsing as an integer */ 1124221420Sdes val = strtol(cp, &ep, 0); 1125221420Sdes if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255) 1126221420Sdes return -1; 1127221420Sdes return val; 1128215116Sdes} 1129221420Sdes 1130226046Sdesconst char * 1131226046Sdesiptos2str(int iptos) 1132226046Sdes{ 1133226046Sdes int i; 1134226046Sdes static char iptos_str[sizeof "0xff"]; 1135226046Sdes 1136226046Sdes for (i = 0; ipqos[i].name != NULL; i++) { 1137226046Sdes if (ipqos[i].value == iptos) 1138226046Sdes return ipqos[i].name; 1139226046Sdes } 1140226046Sdes snprintf(iptos_str, sizeof iptos_str, "0x%02x", iptos); 1141226046Sdes return iptos_str; 1142226046Sdes} 1143262566Sdes 1144204917Sdesvoid 1145262566Sdeslowercase(char *s) 1146262566Sdes{ 1147262566Sdes for (; *s; s++) 1148262566Sdes *s = tolower((u_char)*s); 1149262566Sdes} 1150295367Sdes 1151295367Sdesint 1152295367Sdesunix_listener(const char *path, int backlog, int unlink_first) 1153295367Sdes{ 1154295367Sdes struct sockaddr_un sunaddr; 1155295367Sdes int saved_errno, sock; 1156295367Sdes 1157295367Sdes memset(&sunaddr, 0, sizeof(sunaddr)); 1158295367Sdes sunaddr.sun_family = AF_UNIX; 1159295367Sdes if (strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { 1160295367Sdes error("%s: \"%s\" too long for Unix domain socket", __func__, 1161295367Sdes path); 1162295367Sdes errno = ENAMETOOLONG; 1163295367Sdes return -1; 1164295367Sdes } 1165295367Sdes 1166295367Sdes sock = socket(PF_UNIX, SOCK_STREAM, 0); 1167295367Sdes if (sock < 0) { 1168295367Sdes saved_errno = errno; 1169295367Sdes error("socket: %.100s", strerror(errno)); 1170295367Sdes errno = saved_errno; 1171295367Sdes return -1; 1172295367Sdes } 1173295367Sdes if (unlink_first == 1) { 1174295367Sdes if (unlink(path) != 0 && errno != ENOENT) 1175295367Sdes error("unlink(%s): %.100s", path, strerror(errno)); 1176295367Sdes } 1177295367Sdes if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { 1178295367Sdes saved_errno = errno; 1179295367Sdes error("bind: %.100s", strerror(errno)); 1180295367Sdes close(sock); 1181295367Sdes error("%s: cannot bind to path: %s", __func__, path); 1182295367Sdes errno = saved_errno; 1183295367Sdes return -1; 1184295367Sdes } 1185295367Sdes if (listen(sock, backlog) < 0) { 1186295367Sdes saved_errno = errno; 1187295367Sdes error("listen: %.100s", strerror(errno)); 1188295367Sdes close(sock); 1189295367Sdes unlink(path); 1190295367Sdes error("%s: cannot listen on path: %s", __func__, path); 1191295367Sdes errno = saved_errno; 1192295367Sdes return -1; 1193295367Sdes } 1194295367Sdes return sock; 1195295367Sdes} 1196295367Sdes 1197262566Sdesvoid 1198204917Sdessock_set_v6only(int s) 1199204917Sdes{ 1200296781Sdes#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) 1201204917Sdes int on = 1; 1202204917Sdes 1203204917Sdes debug3("%s: set socket %d IPV6_V6ONLY", __func__, s); 1204204917Sdes if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) 1205204917Sdes error("setsockopt IPV6_V6ONLY: %s", strerror(errno)); 1206204917Sdes#endif 1207204917Sdes} 1208323124Sdes 1209323124Sdes/* 1210323124Sdes * Compares two strings that maybe be NULL. Returns non-zero if strings 1211323124Sdes * are both NULL or are identical, returns zero otherwise. 1212323124Sdes */ 1213323124Sdesstatic int 1214323124Sdesstrcmp_maybe_null(const char *a, const char *b) 1215323124Sdes{ 1216323124Sdes if ((a == NULL && b != NULL) || (a != NULL && b == NULL)) 1217323124Sdes return 0; 1218323124Sdes if (a != NULL && strcmp(a, b) != 0) 1219323124Sdes return 0; 1220323124Sdes return 1; 1221323124Sdes} 1222323124Sdes 1223323124Sdes/* 1224323124Sdes * Compare two forwards, returning non-zero if they are identical or 1225323124Sdes * zero otherwise. 1226323124Sdes */ 1227323124Sdesint 1228323124Sdesforward_equals(const struct Forward *a, const struct Forward *b) 1229323124Sdes{ 1230323124Sdes if (strcmp_maybe_null(a->listen_host, b->listen_host) == 0) 1231323124Sdes return 0; 1232323124Sdes if (a->listen_port != b->listen_port) 1233323124Sdes return 0; 1234323124Sdes if (strcmp_maybe_null(a->listen_path, b->listen_path) == 0) 1235323124Sdes return 0; 1236323124Sdes if (strcmp_maybe_null(a->connect_host, b->connect_host) == 0) 1237323124Sdes return 0; 1238323124Sdes if (a->connect_port != b->connect_port) 1239323124Sdes return 0; 1240323124Sdes if (strcmp_maybe_null(a->connect_path, b->connect_path) == 0) 1241323124Sdes return 0; 1242323124Sdes /* allocated_port and handle are not checked */ 1243323124Sdes return 1; 1244323124Sdes} 1245323124Sdes 1246