X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/c5d10563138ba0f06f531c176e59ba06401386f5..d59ac96c02231e8067fc89f55a31d7639eb11c6e:/misc.c diff --git a/misc.c b/misc.c index 96d90dec..b260d89f 100644 --- a/misc.c +++ b/misc.c @@ -1,6 +1,7 @@ +/* $OpenBSD: misc.c,v 1.74 2009/12/25 19:40:21 stevesk Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. - * Copyright (c) 2005 Damien Miller. All rights reserved. + * Copyright (c) 2005,2006 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,18 +26,35 @@ #include "includes.h" +#include #include +#include +#include + +#include +#include +#include +#include +#include + +#include #include + +#include +#include +#include #ifdef HAVE_PATHS_H # include +#include #endif #ifdef SSH_TUN_OPENBSD #include #endif +#include "xmalloc.h" #include "misc.h" #include "log.h" -#include "xmalloc.h" +#include "ssh.h" /* remove newline at end of string */ char * @@ -103,6 +121,14 @@ unset_nonblock(int fd) return (0); } +const char * +ssh_gai_strerror(int gaierr) +{ + if (gaierr == EAI_SYSTEM) + return strerror(errno); + return gai_strerror(gaierr); +} + /* disable nagle on socket */ void set_nodelay(int fd) @@ -125,6 +151,47 @@ set_nodelay(int fd) error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); } +/* open a socket in the specified routing domain */ +int +socket_rdomain(int domain, int type, int protocol, int rdomain) +{ + int sock, ipproto = IPPROTO_IP; + + if ((sock = socket(domain, type, protocol)) == -1) + return (-1); + + if (rdomain == -1) + return (sock); + + switch (domain) { +#ifdef IPPROTO_IPV6 + case AF_INET6: + ipproto = IPPROTO_IPV6; + /* FALLTHROUGH */ +#endif + case AF_INET: +#ifdef USE_ROUTINGDOMAIN + debug2("socket %d af %d setting rdomain %d", + sock, domain, rdomain); + if (setsockopt(sock, ipproto, SO_RDOMAIN, &rdomain, + sizeof(rdomain)) == -1) { + debug("setsockopt SO_RDOMAIN: %.100s", + strerror(errno)); + close(sock); + return (-1); + } +#endif + break; + default: + debug("socket %d af %d does not support rdomain %d", + sock, domain, rdomain); + close(sock); + return (-1); + } + + return (sock); +} + /* Characters considered whitespace in strsep calls. */ #define WHITESPACE " \t\r\n" #define QUOTE "\"" @@ -195,24 +262,34 @@ pwcopy(struct passwd *pw) /* * Convert ASCII string to TCP/IP port number. - * Port must be >0 and <=65535. - * Return 0 if invalid. + * Port must be >=0 and <=65535. + * Return -1 if invalid. */ int a2port(const char *s) { - long port; - char *endp; + long long port; + const char *errstr; - errno = 0; - port = strtol(s, &endp, 0); - if (s == endp || *endp != '\0' || - (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || - port <= 0 || port > 65535) - return 0; + port = strtonum(s, 0, 65535, &errstr); + if (errstr != NULL) + return -1; + return (int)port; +} - return port; +#ifdef USE_ROUTINGDOMAIN +int +a2rdomain(const char *s) +{ + long long rdomain; + const char *errstr; + + rdomain = strtonum(s, 0, RT_TABLEID_MAX, &errstr); + if (errstr != NULL) + return -1; + return (int)rdomain; } +#endif int a2tun(const char *s, int *remote) @@ -328,6 +405,23 @@ convtime(const char *s) return total; } +/* + * Returns a standardized host+port identifier string. + * Caller must free returned string. + */ +char * +put_host_port(const char *host, u_short port) +{ + char *hoststr; + + if (port == 0 || port == SSH_DEFAULT_PORT) + return(xstrdup(host)); + if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0) + fatal("put_host_port: asprintf: %s", strerror(errno)); + debug3("put_host_port: %s", hoststr); + return hoststr; +} + /* * Search for next delimiter between hostnames/addresses and ports. * Argument may be modified (for termination). @@ -491,7 +585,7 @@ tilde_expand_filename(const char *filename, uid_t uid) if ((pw = getpwnam(user)) == NULL) fatal("tilde_expand_filename: No such user %s", user); } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ - fatal("tilde_expand_filename: No such uid %d", uid); + fatal("tilde_expand_filename: No such uid %ld", (long)uid); if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret)) fatal("tilde_expand_filename: Path too long"); @@ -521,11 +615,11 @@ char * percent_expand(const char *string, ...) { #define EXPAND_MAX_KEYS 16 + u_int num_keys, i, j; struct { const char *key; const char *repl; } keys[EXPAND_MAX_KEYS]; - u_int num_keys, i, j; char buf[4096]; va_list ap; @@ -537,13 +631,12 @@ percent_expand(const char *string, ...) break; keys[num_keys].repl = va_arg(ap, char *); if (keys[num_keys].repl == NULL) - fatal("percent_expand: NULL replacement"); + fatal("%s: NULL replacement", __func__); } + if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) + fatal("%s: too many keys", __func__); va_end(ap); - if (num_keys >= EXPAND_MAX_KEYS) - fatal("percent_expand: too many keys"); - /* Expand string */ *buf = '\0'; for (i = 0; *string != '\0'; string++) { @@ -551,23 +644,24 @@ percent_expand(const char *string, ...) append: buf[i++] = *string; if (i >= sizeof(buf)) - fatal("percent_expand: string too long"); + fatal("%s: string too long", __func__); buf[i] = '\0'; continue; } string++; + /* %% case */ if (*string == '%') goto append; for (j = 0; j < num_keys; j++) { if (strchr(keys[j].key, *string) != NULL) { i = strlcat(buf, keys[j].repl, sizeof(buf)); if (i >= sizeof(buf)) - fatal("percent_expand: string too long"); + fatal("%s: string too long", __func__); break; } } if (j >= num_keys) - fatal("percent_expand: unknown key %%%c", *string); + fatal("%s: unknown key %%%c", __func__, *string); } return (xstrdup(buf)); #undef EXPAND_MAX_KEYS @@ -582,6 +676,8 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, u_long *lineno) { while (fgets(buf, bufsz, f) != NULL) { + if (buf[0] == '\0') + continue; (*lineno)++; if (buf[strlen(buf) - 1] == '\n' || feof(f)) { return 0; @@ -673,7 +769,8 @@ sanitise_stdfd(void) int nullfd, dupfd; if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { - fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); + fprintf(stderr, "Couldn't open /dev/null: %s\n", + strerror(errno)); exit(1); } while (++dupfd <= 2) { @@ -681,7 +778,7 @@ sanitise_stdfd(void) if (fcntl(dupfd, F_GETFL, 0) >= 0) continue; if (dup2(nullfd, dupfd) == -1) { - fprintf(stderr, "dup2: %s", strerror(errno)); + fprintf(stderr, "dup2: %s\n", strerror(errno)); exit(1); } } @@ -690,17 +787,131 @@ sanitise_stdfd(void) } char * -tohex(const u_char *d, u_int l) +tohex(const void *vp, size_t l) { + const u_char *p = (const u_char *)vp; char b[3], *r; - u_int i, hl; + size_t i, hl; + + if (l > 65536) + return xstrdup("tohex: length > 65536"); hl = l * 2 + 1; r = xcalloc(1, hl); for (i = 0; i < l; i++) { - snprintf(b, sizeof(b), "%02x", d[i]); + snprintf(b, sizeof(b), "%02x", p[i]); strlcat(r, b, hl); } return (r); } +u_int64_t +get_u64(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int64_t v; + + v = (u_int64_t)p[0] << 56; + v |= (u_int64_t)p[1] << 48; + v |= (u_int64_t)p[2] << 40; + v |= (u_int64_t)p[3] << 32; + v |= (u_int64_t)p[4] << 24; + v |= (u_int64_t)p[5] << 16; + v |= (u_int64_t)p[6] << 8; + v |= (u_int64_t)p[7]; + + return (v); +} + +u_int32_t +get_u32(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int32_t v; + + v = (u_int32_t)p[0] << 24; + v |= (u_int32_t)p[1] << 16; + v |= (u_int32_t)p[2] << 8; + v |= (u_int32_t)p[3]; + + return (v); +} + +u_int16_t +get_u16(const void *vp) +{ + const u_char *p = (const u_char *)vp; + u_int16_t v; + + v = (u_int16_t)p[0] << 8; + v |= (u_int16_t)p[1]; + + return (v); +} + +void +put_u64(void *vp, u_int64_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 56) & 0xff; + p[1] = (u_char)(v >> 48) & 0xff; + p[2] = (u_char)(v >> 40) & 0xff; + p[3] = (u_char)(v >> 32) & 0xff; + p[4] = (u_char)(v >> 24) & 0xff; + p[5] = (u_char)(v >> 16) & 0xff; + p[6] = (u_char)(v >> 8) & 0xff; + p[7] = (u_char)v & 0xff; +} + +void +put_u32(void *vp, u_int32_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 24) & 0xff; + p[1] = (u_char)(v >> 16) & 0xff; + p[2] = (u_char)(v >> 8) & 0xff; + p[3] = (u_char)v & 0xff; +} + + +void +put_u16(void *vp, u_int16_t v) +{ + u_char *p = (u_char *)vp; + + p[0] = (u_char)(v >> 8) & 0xff; + p[1] = (u_char)v & 0xff; +} + +void +ms_subtract_diff(struct timeval *start, int *ms) +{ + struct timeval diff, finish; + + gettimeofday(&finish, NULL); + timersub(&finish, start, &diff); + *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000); +} + +void +ms_to_timeval(struct timeval *tv, int ms) +{ + if (ms < 0) + ms = 0; + tv->tv_sec = ms / 1000; + tv->tv_usec = (ms % 1000) * 1000; +} + +void +sock_set_v6only(int s) +{ +#ifdef IPV6_V6ONLY + int on = 1; + + debug3("%s: set socket %d IPV6_V6ONLY", __func__, s); + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) + error("setsockopt IPV6_V6ONLY: %s", strerror(errno)); +#endif +}