This commit is contained in:
Manoj Ampalam 2017-11-16 14:03:24 -08:00
commit 2846d75e56
60 changed files with 1899 additions and 809 deletions

View File

@ -1,3 +1,7 @@
# Commit IDs against the new CVS->GIT translation go here (and delete this line)
Old upstream tree:
321065a95a7ccebdd5fd08482a1e19afbf524e35 Update DH groups
d4f699a421504df35254cf1c6f1a7c304fb907ca Remove 1k bit groups
aafe246655b53b52bc32c8a24002bc262f4230f7 Remove intermediate moduli

View File

@ -100,9 +100,9 @@ DSA certificate
ECDSA certificate
string "ecdsa-sha2-nistp256-v01@openssh.com" |
"ecdsa-sha2-nistp384-v01@openssh.com" |
"ecdsa-sha2-nistp521-v01@openssh.com"
string "ecdsa-sha2-nistp256-cert-v01@openssh.com" |
"ecdsa-sha2-nistp384-cert-v01@openssh.com" |
"ecdsa-sha2-nistp521-cert-v01@openssh.com"
string nonce
string curve
string public_key
@ -291,4 +291,4 @@ permit-user-rc empty Flag indicating that execution of
of this script will not be permitted if
this option is not present.
$OpenBSD: PROTOCOL.certkeys,v 1.12 2017/05/31 04:29:44 djm Exp $
$OpenBSD: PROTOCOL.certkeys,v 1.13 2017/11/03 02:32:19 djm Exp $

View File

@ -1,3 +1,4 @@
/* $OpenBSD: bitmap.c,v 1.9 2017/10/20 01:56:39 djm Exp $ */
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*

View File

@ -1,3 +1,4 @@
/* $OpenBSD: bitmap.h,v 1.2 2017/10/20 01:56:39 djm Exp $ */
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.375 2017/09/24 13:45:34 djm Exp $ */
/* $OpenBSD: channels.c,v 1.376 2017/10/25 00:15:35 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1668,19 +1668,6 @@ port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
free(local_ipaddr);
}
static void
channel_set_reuseaddr(int fd)
{
int on = 1;
/*
* Set socket options.
* Allow local port reuse in TIME_WAIT.
*/
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
}
void
channel_set_x11_refuse_time(struct ssh *ssh, u_int refuse_time)
{
@ -3370,7 +3357,7 @@ channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type,
continue;
}
channel_set_reuseaddr(sock);
set_reuseaddr(sock);
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
@ -4443,7 +4430,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset,
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
if (x11_use_localhost)
channel_set_reuseaddr(sock);
set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
debug2("%s: bind port %d: %.100s", __func__,
port, strerror(errno));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: cipher.c,v 1.107 2017/05/07 23:12:57 djm Exp $ */
/* $OpenBSD: cipher.c,v 1.108 2017/11/03 02:22:41 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -449,8 +449,8 @@ cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
int
cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
{
const struct sshcipher *c = cc->cipher;
#ifdef WITH_OPENSSL
const struct sshcipher *c = cc->cipher;
int evplen;
#endif
@ -494,8 +494,8 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
int
cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
{
const struct sshcipher *c = cc->cipher;
#ifdef WITH_OPENSSL
const struct sshcipher *c = cc->cipher;
int evplen = 0;
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.305 2017/09/19 04:24:22 djm Exp $ */
/* $OpenBSD: clientloop.c,v 1.306 2017/10/23 05:08:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1605,12 +1605,13 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
return c;
}
int
char *
client_request_tun_fwd(struct ssh *ssh, int tun_mode,
int local_tun, int remote_tun)
{
Channel *c;
int fd;
char *ifname = NULL;
if (tun_mode == SSH_TUNMODE_NO)
return 0;
@ -1618,10 +1619,11 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode,
debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
/* Open local tunnel device */
if ((fd = tun_open(local_tun, tun_mode)) == -1) {
if ((fd = tun_open(local_tun, tun_mode, &ifname)) == -1) {
error("Tunnel device open failed.");
return -1;
return NULL;
}
debug("Tunnel forwarding using interface %s", ifname);
c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
@ -1642,7 +1644,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode,
packet_put_int(remote_tun);
packet_send();
return 0;
return ifname;
}
/* XXXX move to generic input handler */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.34 2017/09/12 06:32:07 djm Exp $ */
/* $OpenBSD: clientloop.h,v 1.35 2017/10/23 05:08:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -46,7 +46,7 @@ int client_x11_get_proto(struct ssh *, const char *, const char *,
void client_global_request_reply_fwd(int, u_int32_t, void *);
void client_session2_setup(struct ssh *, int, int, int,
const char *, struct termios *, int, Buffer *, char **);
int client_request_tun_fwd(struct ssh *, int, int, int);
char *client_request_tun_fwd(struct ssh *, int, int, int);
void client_stop_mux(void);
/* Escape filter for protocol 2 sessions */

View File

@ -427,6 +427,16 @@ AC_CHECK_HEADERS([sys/capsicum.h], [], [], [
#endif
])
# net/route.h requires sys/socket.h and sys/types.h.
# sys/sysctl.h also requires sys/param.h
AC_CHECK_HEADERS([net/route.h sys/sysctl.h], [], [], [
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/socket.h>
])
# lastlog.h requires sys/time.h to be included first on Solaris
AC_CHECK_HEADERS([lastlog.h], [], [], [
#ifdef HAVE_SYS_TIME_H
@ -769,6 +779,9 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
[Prepend the address family to IP tunnel traffic])
fi
AC_CHECK_HEADER([linux/if.h],
AC_DEFINE([SYS_RDOMAIN_LINUX], [1],
[Support routing domains using Linux VRF]))
AC_CHECK_HEADERS([linux/seccomp.h linux/filter.h linux/audit.h], [],
[], [#include <linux/types.h>])
AC_MSG_CHECKING([for seccomp architecture])

3
dh.c
View File

@ -25,6 +25,7 @@
#include "includes.h"
#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#include <openssl/dh.h>
@ -465,3 +466,5 @@ dh_estimate(int bits)
return 7680;
return 8192;
}
#endif /* WITH_OPENSSL */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexc25519s.c,v 1.10 2015/12/04 16:41:28 markus Exp $ */
/* $OpenBSD: kexc25519s.c,v 1.11 2017/05/31 04:19:28 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.

375
misc.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
/* $OpenBSD: misc.c,v 1.118 2017/10/25 00:17:08 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -167,6 +167,73 @@ set_nodelay(int fd)
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
}
/* Allow local port reuse in TIME_WAIT */
int
set_reuseaddr(int fd)
{
int on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
return -1;
}
return 0;
}
/* Get/set routing domain */
char *
get_rdomain(int fd)
{
#if defined(HAVE_SYS_GET_RDOMAIN)
return sys_get_rdomain(fd);
#elif defined(__OpenBSD__)
int rtable;
char *ret;
socklen_t len = sizeof(rtable);
if (getsockopt(fd, SOL_SOCKET, SO_RTABLE, &rtable, &len) == -1) {
error("Failed to get routing domain for fd %d: %s",
fd, strerror(errno));
return NULL;
}
xasprintf(&ret, "%d", rtable);
return ret;
#else /* defined(__OpenBSD__) */
return NULL;
#endif
}
int
set_rdomain(int fd, const char *name)
{
#if defined(HAVE_SYS_SET_RDOMAIN)
return sys_set_rdomain(fd, name);
#elif defined(__OpenBSD__)
int rtable;
const char *errstr;
if (name == NULL)
return 0; /* default table */
rtable = (int)strtonum(name, 0, 255, &errstr);
if (errstr != NULL) {
/* Shouldn't happen */
error("Invalid routing domain \"%s\": %s", name, errstr);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_RTABLE,
&rtable, sizeof(rtable)) == -1) {
error("Failed to set routing domain %d on fd %d: %s",
rtable, fd, strerror(errno));
return -1;
}
return 0;
#else /* defined(__OpenBSD__) */
error("Setting routing domain is not supported on this platform");
return -1;
#endif
}
/* Characters considered whitespace in strsep calls. */
#define WHITESPACE " \t\r\n"
#define QUOTE "\""
@ -399,11 +466,12 @@ put_host_port(const char *host, u_short port)
* Search for next delimiter between hostnames/addresses and ports.
* Argument may be modified (for termination).
* Returns *cp if parsing succeeds.
* *cp is set to the start of the next delimiter, if one was found.
* *cp is set to the start of the next field, if one was found.
* The delimiter char, if present, is stored in delim.
* If this is the last field, *cp is set to NULL.
*/
char *
hpdelim(char **cp)
static char *
hpdelim2(char **cp, char *delim)
{
char *s, *old;
@ -426,6 +494,8 @@ hpdelim(char **cp)
case ':':
case '/':
if (delim != NULL)
*delim = *s;
*s = '\0'; /* terminate */
*cp = s + 1;
break;
@ -437,6 +507,12 @@ hpdelim(char **cp)
return old;
}
char *
hpdelim(char **cp)
{
return hpdelim2(cp, NULL);
}
char *
cleanhostname(char *host)
{
@ -481,6 +557,75 @@ colon(char *cp)
return NULL;
}
/*
* Parse a [user@]host:[path] string.
* Caller must free returned user, host and path.
* Any of the pointer return arguments may be NULL (useful for syntax checking).
* If user was not specified then *userp will be set to NULL.
* If host was not specified then *hostp will be set to NULL.
* If path was not specified then *pathp will be set to ".".
* Returns 0 on success, -1 on failure.
*/
int
parse_user_host_path(const char *s, char **userp, char **hostp, char **pathp)
{
char *user = NULL, *host = NULL, *path = NULL;
char *sdup, *tmp;
int ret = -1;
if (userp != NULL)
*userp = NULL;
if (hostp != NULL)
*hostp = NULL;
if (pathp != NULL)
*pathp = NULL;
sdup = xstrdup(s);
/* Check for remote syntax: [user@]host:[path] */
if ((tmp = colon(sdup)) == NULL)
goto out;
/* Extract optional path */
*tmp++ = '\0';
if (*tmp == '\0')
tmp = ".";
path = xstrdup(tmp);
/* Extract optional user and mandatory host */
tmp = strrchr(sdup, '@');
if (tmp != NULL) {
*tmp++ = '\0';
host = xstrdup(cleanhostname(tmp));
if (*sdup != '\0')
user = xstrdup(sdup);
} else {
host = xstrdup(cleanhostname(sdup));
user = NULL;
}
/* Success */
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (pathp != NULL) {
*pathp = path;
path = NULL;
}
ret = 0;
out:
free(sdup);
free(user);
free(host);
free(path);
return ret;
}
/*
* Parse a [user@]host[:port] string.
* Caller must free returned user and host.
@ -506,7 +651,7 @@ parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
if ((sdup = tmp = strdup(s)) == NULL)
return -1;
/* Extract optional username */
if ((cp = strchr(tmp, '@')) != NULL) {
if ((cp = strrchr(tmp, '@')) != NULL) {
*cp = '\0';
if (*tmp == '\0')
goto out;
@ -542,6 +687,168 @@ parse_user_host_port(const char *s, char **userp, char **hostp, int *portp)
return ret;
}
/*
* Converts a two-byte hex string to decimal.
* Returns the decimal value or -1 for invalid input.
*/
static int
hexchar(const char *s)
{
unsigned char result[2];
int i;
for (i = 0; i < 2; i++) {
if (s[i] >= '0' && s[i] <= '9')
result[i] = (unsigned char)(s[i] - '0');
else if (s[i] >= 'a' && s[i] <= 'f')
result[i] = (unsigned char)(s[i] - 'a') + 10;
else if (s[i] >= 'A' && s[i] <= 'F')
result[i] = (unsigned char)(s[i] - 'A') + 10;
else
return -1;
}
return (result[0] << 4) | result[1];
}
/*
* Decode an url-encoded string.
* Returns a newly allocated string on success or NULL on failure.
*/
static char *
urldecode(const char *src)
{
char *ret, *dst;
int ch;
ret = xmalloc(strlen(src) + 1);
for (dst = ret; *src != '\0'; src++) {
switch (*src) {
case '+':
*dst++ = ' ';
break;
case '%':
if (!isxdigit((unsigned char)src[1]) ||
!isxdigit((unsigned char)src[2]) ||
(ch = hexchar(src + 1)) == -1) {
free(ret);
return NULL;
}
*dst++ = ch;
src += 2;
break;
default:
*dst++ = *src;
break;
}
}
*dst = '\0';
return ret;
}
/*
* Parse an (scp|ssh|sftp)://[user@]host[:port][/path] URI.
* See https://tools.ietf.org/html/draft-ietf-secsh-scp-sftp-ssh-uri-04
* Either user or path may be url-encoded (but not host or port).
* Caller must free returned user, host and path.
* Any of the pointer return arguments may be NULL (useful for syntax checking)
* but the scheme must always be specified.
* If user was not specified then *userp will be set to NULL.
* If port was not specified then *portp will be -1.
* If path was not specified then *pathp will be set to NULL.
* Returns 0 on success, 1 if non-uri/wrong scheme, -1 on error/invalid uri.
*/
int
parse_uri(const char *scheme, const char *uri, char **userp, char **hostp,
int *portp, char **pathp)
{
char *uridup, *cp, *tmp, ch;
char *user = NULL, *host = NULL, *path = NULL;
int port = -1, ret = -1;
size_t len;
len = strlen(scheme);
if (strncmp(uri, scheme, len) != 0 || strncmp(uri + len, "://", 3) != 0)
return 1;
uri += len + 3;
if (userp != NULL)
*userp = NULL;
if (hostp != NULL)
*hostp = NULL;
if (portp != NULL)
*portp = -1;
if (pathp != NULL)
*pathp = NULL;
uridup = tmp = xstrdup(uri);
/* Extract optional ssh-info (username + connection params) */
if ((cp = strchr(tmp, '@')) != NULL) {
char *delim;
*cp = '\0';
/* Extract username and connection params */
if ((delim = strchr(tmp, ';')) != NULL) {
/* Just ignore connection params for now */
*delim = '\0';
}
if (*tmp == '\0') {
/* Empty username */
goto out;
}
if ((user = urldecode(tmp)) == NULL)
goto out;
tmp = cp + 1;
}
/* Extract mandatory hostname */
if ((cp = hpdelim2(&tmp, &ch)) == NULL || *cp == '\0')
goto out;
host = xstrdup(cleanhostname(cp));
if (!valid_domain(host, 0, NULL))
goto out;
if (tmp != NULL && *tmp != '\0') {
if (ch == ':') {
/* Convert and verify port. */
if ((cp = strchr(tmp, '/')) != NULL)
*cp = '\0';
if ((port = a2port(tmp)) <= 0)
goto out;
tmp = cp ? cp + 1 : NULL;
}
if (tmp != NULL && *tmp != '\0') {
/* Extract optional path */
if ((path = urldecode(tmp)) == NULL)
goto out;
}
}
/* Success */
if (userp != NULL) {
*userp = user;
user = NULL;
}
if (hostp != NULL) {
*hostp = host;
host = NULL;
}
if (portp != NULL)
*portp = port;
if (pathp != NULL) {
*pathp = path;
path = NULL;
}
ret = 0;
out:
free(uridup);
free(user);
free(host);
free(path);
return ret;
}
/* function to assist building execv() arguments */
void
addargs(arglist *args, char *fmt, ...)
@ -739,16 +1046,19 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
}
int
tun_open(int tun, int mode)
tun_open(int tun, int mode, char **ifname)
{
#if defined(CUSTOM_SYS_TUN_OPEN)
return (sys_tun_open(tun, mode));
return (sys_tun_open(tun, mode, ifname));
#elif defined(SSH_TUN_OPENBSD)
struct ifreq ifr;
char name[100];
int fd = -1, sock;
const char *tunbase = "tun";
if (ifname != NULL)
*ifname = NULL;
if (mode == SSH_TUNMODE_ETHERNET)
tunbase = "tap";
@ -795,6 +1105,9 @@ tun_open(int tun, int mode)
}
}
if (ifname != NULL)
*ifname = xstrdup(ifr.ifr_name);
close(sock);
return fd;
@ -1775,3 +2088,51 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
}
/*
* Check and optionally lowercase a domain name, also removes trailing '.'
* Returns 1 on success and 0 on failure, storing an error message in errstr.
*/
int
valid_domain(char *name, int makelower, const char **errstr)
{
size_t i, l = strlen(name);
u_char c, last = '\0';
static char errbuf[256];
if (l == 0) {
strlcpy(errbuf, "empty domain name", sizeof(errbuf));
goto bad;
}
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) {
snprintf(errbuf, sizeof(errbuf), "domain name \"%.100s\" "
"starts with invalid character", name);
goto bad;
}
for (i = 0; i < l; i++) {
c = tolower((u_char)name[i]);
if (makelower)
name[i] = (char)c;
if (last == '.' && c == '.') {
snprintf(errbuf, sizeof(errbuf), "domain name "
"\"%.100s\" contains consecutive separators", name);
goto bad;
}
if (c != '.' && c != '-' && !isalnum(c) &&
c != '_') /* technically invalid, but common */ {
snprintf(errbuf, sizeof(errbuf), "domain name "
"\"%.100s\" contains invalid characters", name);
goto bad;
}
last = c;
}
if (name[l - 1] == '.')
name[l - 1] = '\0';
if (errstr != NULL)
*errstr = NULL;
return 1;
bad:
if (errstr != NULL)
*errstr = errbuf;
return 0;
}

10
misc.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.63 2017/08/18 05:48:04 djm Exp $ */
/* $OpenBSD: misc.h,v 1.67 2017/10/25 00:17:08 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -48,13 +48,18 @@ char *strdelim(char **);
int set_nonblock(int);
int unset_nonblock(int);
void set_nodelay(int);
int set_reuseaddr(int);
char *get_rdomain(int);
int set_rdomain(int, const char *);
int a2port(const char *);
int a2tun(const char *, int *);
char *put_host_port(const char *, u_short);
char *hpdelim(char **);
char *cleanhostname(char *);
char *colon(char *);
int parse_user_host_path(const char *, char **, char **, char **);
int parse_user_host_port(const char *, char **, char **, int *);
int parse_uri(const char *, const char *, char **, char **, int *, char **);
long convtime(const char *);
char *tilde_expand_filename(const char *, uid_t);
char *percent_expand(const char *, ...) __attribute__((__sentinel__));
@ -66,6 +71,7 @@ time_t monotime(void);
double monotime_double(void);
void lowercase(char *s);
int unix_listener(const char *, int, int);
int valid_domain(char *, int, const char **);
void sock_set_v6only(int);
@ -84,7 +90,7 @@ void replacearg(arglist *, u_int, char *, ...)
__attribute__((format(printf, 3, 4)));
void freeargs(arglist *);
int tun_open(int, int);
int tun_open(int, int, char **);
/* Common definitions for ssh tunnel device forwarding */
#define SSH_TUNMODE_NO 0x00

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.174 2017/10/02 19:33:20 djm Exp $ */
/* $OpenBSD: monitor.c,v 1.175 2017/10/05 15:52:03 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -760,12 +760,10 @@ mm_answer_pwnamallow(int sock, Buffer *m)
for (i = 0; i < options.nx; i++) \
buffer_put_cstring(m, options.x[i]); \
} while (0)
#define M_CP_STRARRAYOPT_ALLOC(x, nx) M_CP_STRARRAYOPT(x, nx)
/* See comment in servconf.h */
COPY_MATCH_STRING_OPTS();
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
#undef M_CP_STRARRAYOPT_ALLOC
/* Create valid auth method lists */
if (auth2_setup_methods_lists(authctxt) != 0) {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor_wrap.c,v 1.94 2017/10/02 19:33:20 djm Exp $ */
/* $OpenBSD: monitor_wrap.c,v 1.95 2017/10/05 15:52:03 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -287,19 +287,15 @@ out:
newopts->x = buffer_get_string(&m, NULL); \
} while (0)
#define M_CP_STRARRAYOPT(x, nx) do { \
for (i = 0; i < newopts->nx; i++) \
newopts->x[i] = buffer_get_string(&m, NULL); \
} while (0)
#define M_CP_STRARRAYOPT_ALLOC(x, nx) do { \
newopts->x = newopts->nx == 0 ? \
NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \
M_CP_STRARRAYOPT(x, nx); \
for (i = 0; i < newopts->nx; i++) \
newopts->x[i] = buffer_get_string(&m, NULL); \
} while (0)
/* See comment in servconf.h */
COPY_MATCH_STRING_OPTS();
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
#undef M_CP_STRARRAYOPT_ALLOC
copy_set_server_options(&options, newopts, 1);
log_change_level(options.log_level);

View File

@ -1,3 +1,4 @@
/* $OpenBSD: opacket.c,v 1.7 2017/10/20 01:56:39 djm Exp $ */
/* Written by Markus Friedl. Placed in the public domain. */
#include "includes.h"

View File

@ -1,3 +1,4 @@
/* $OpenBSD: opacket.h,v 1.12 2017/10/20 01:56:39 djm Exp $ */
#ifndef _OPACKET_H
/* Written by Markus Friedl. Placed in the public domain. */

View File

@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di
COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-getpagesize.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-malloc.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-net.o port-uw.o
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<

View File

@ -1,5 +1,7 @@
/* Placed in the public domain */
#include "includes.h"
#ifndef HAVE_GETPAGESIZE
#include <unistd.h>

View File

@ -325,7 +325,7 @@ char *shadow_pw(struct passwd *pw);
#include "port-irix.h"
#include "port-linux.h"
#include "port-solaris.h"
#include "port-tun.h"
#include "port-net.h"
#include "port-uw.h"
/* _FORTIFY_SOURCE breaks FD_ISSET(n)/FD_SET(n) for n > FD_SETSIZE. Avoid. */

View File

@ -36,6 +36,90 @@
#include "channels.h"
#include "ssherr.h"
/*
* This file contains various portability code for network support,
* including tun/tap forwarding and routing domains.
*/
#if defined(SYS_RDOMAIN_LINUX) || defined(SSH_TUN_LINUX)
#include <linux/if.h>
#endif
#if defined(SYS_RDOMAIN_LINUX)
char *
sys_get_rdomain(int fd)
{
char dev[IFNAMSIZ + 1];
socklen_t len = sizeof(dev) - 1;
if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, dev, &len) == -1) {
error("%s: cannot determine VRF for fd=%d : %s",
__func__, fd, strerror(errno));
return NULL;
}
dev[len] = '\0';
return strdup(dev);
}
int
sys_set_rdomain(int fd, const char *name)
{
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
name, strlen(name)) == -1) {
error("%s: setsockopt(%d, SO_BINDTODEVICE, %s): %s",
__func__, fd, name, strerror(errno));
return -1;
}
return 0;
}
int
sys_valid_rdomain(const char *name)
{
int fd;
/*
* This is a pretty crappy way to test. It would be better to
* check whether "name" represents a VRF device, but apparently
* that requires an rtnetlink transaction.
*/
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return 0;
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
name, strlen(name)) == -1) {
close(fd);
return 0;
}
close(fd);
return 1;
}
#elif defined(SYS_RDOMAIN_XXX)
/* XXX examples */
char *
sys_get_rdomain(int fd)
{
return NULL;
}
int
sys_set_rdomain(int fd, const char *name)
{
return -1;
}
int
valid_rdomain(const char *name)
{
return 0;
}
void
sys_set_process_rdomain(const char *name)
{
fatal("%s: not supported", __func__);
}
#endif /* defined(SYS_RDOMAIN_XXX) */
/*
* This is the portable version of the SSH tunnel forwarding, it
* uses some preprocessor definitions for various platform-specific
@ -52,16 +136,18 @@
*/
#if defined(SSH_TUN_LINUX)
#include <linux/if.h>
#include <linux/if_tun.h>
int
sys_tun_open(int tun, int mode)
sys_tun_open(int tun, int mode, char **ifname)
{
struct ifreq ifr;
int fd = -1;
const char *name = NULL;
if (ifname != NULL)
*ifname = NULL;
if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
debug("%s: failed to open tunnel control interface: %s",
__func__, strerror(errno));
@ -99,6 +185,9 @@ sys_tun_open(int tun, int mode)
else
debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)))
goto failed;
return (fd);
failed:
@ -116,13 +205,16 @@ sys_tun_open(int tun, int mode)
#endif
int
sys_tun_open(int tun, int mode)
sys_tun_open(int tun, int mode, char **ifname)
{
struct ifreq ifr;
char name[100];
int fd = -1, sock, flag;
const char *tunbase = "tun";
if (ifname != NULL)
*ifname = NULL;
if (mode == SSH_TUNMODE_ETHERNET) {
#ifdef SSH_TUN_NO_L2
debug("%s: no layer 2 tunnelling support", __func__);
@ -180,6 +272,9 @@ sys_tun_open(int tun, int mode)
goto failed;
}
if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)))
goto failed;
close(sock);
return (fd);

View File

@ -22,7 +22,7 @@ struct ssh;
#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
# define CUSTOM_SYS_TUN_OPEN
int sys_tun_open(int, int);
int sys_tun_open(int, int, char **);
#endif
#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
@ -31,4 +31,18 @@ int sys_tun_infilter(struct ssh *, struct Channel *, char *, int);
u_char *sys_tun_outfilter(struct ssh *, struct Channel *, u_char **, size_t *);
#endif
#if defined(SYS_RDOMAIN_LINUX)
# define HAVE_SYS_GET_RDOMAIN
# define HAVE_SYS_SET_RDOMAIN
# define HAVE_SYS_VALID_RDOMAIN
char *sys_get_rdomain(int fd);
int sys_set_rdomain(int fd, const char *name);
int sys_valid_rdomain(const char *name);
#endif
#if defined(SYS_RDOMAIN_XXX)
# define HAVE_SYS_SET_PROCESS_RDOMAIN
void sys_set_process_rdomain(const char *name);
#endif
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.264 2017/09/12 06:32:07 djm Exp $ */
/* $OpenBSD: packet.c,v 1.266 2017/10/25 00:17:08 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -557,6 +557,18 @@ ssh_local_port(struct ssh *ssh)
return ssh->local_port;
}
/* Returns the routing domain of the input socket, or NULL if unavailable */
const char *
ssh_packet_rdomain_in(struct ssh *ssh)
{
if (ssh->rdomain_in != NULL)
return ssh->rdomain_in;
if (!ssh_packet_connection_is_on_socket(ssh))
return NULL;
ssh->rdomain_in = get_rdomain(ssh->state->connection_in);
return ssh->rdomain_in;
}
/* Closes the connection and clears and frees internal data structures. */
static void
@ -1774,6 +1786,8 @@ ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
debug3("sending debug message: %s", buf);
if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.h,v 1.82 2017/09/12 06:32:07 djm Exp $ */
/* $OpenBSD: packet.h,v 1.83 2017/10/25 00:17:08 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -61,6 +61,7 @@ struct ssh {
int remote_port;
char *local_ipaddr;
int local_port;
char *rdomain_in;
/* Optional preamble for log messages (e.g. username) */
char *log_preamble;
@ -162,6 +163,7 @@ const char *ssh_remote_ipaddr(struct ssh *);
int ssh_remote_port(struct ssh *);
const char *ssh_local_ipaddr(struct ssh *);
int ssh_local_port(struct ssh *);
const char *ssh_packet_rdomain_in(struct ssh *);
void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, u_int32_t);
time_t ssh_packet_get_rekey_timeout(struct ssh *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.279 2017/09/21 19:16:53 markus Exp $ */
/* $OpenBSD: readconf.c,v 1.280 2017/10/21 23:06:24 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -689,34 +689,6 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
return result;
}
/* Check and prepare a domain name: removes trailing '.' and lowercases */
static void
valid_domain(char *name, const char *filename, int linenum)
{
size_t i, l = strlen(name);
u_char c, last = '\0';
if (l == 0)
fatal("%s line %d: empty hostname suffix", filename, linenum);
if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0]))
fatal("%s line %d: hostname suffix \"%.100s\" "
"starts with invalid character", filename, linenum, name);
for (i = 0; i < l; i++) {
c = tolower((u_char)name[i]);
name[i] = (char)c;
if (last == '.' && c == '.')
fatal("%s line %d: hostname suffix \"%.100s\" contains "
"consecutive separators", filename, linenum, name);
if (c != '.' && c != '-' && !isalnum(c) &&
c != '_') /* technically invalid, but common */
fatal("%s line %d: hostname suffix \"%.100s\" contains "
"invalid characters", filename, linenum, name);
last = c;
}
if (name[l - 1] == '.')
name[l - 1] = '\0';
}
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@ -1568,7 +1540,11 @@ parse_keytypes:
case oCanonicalDomains:
value = options->num_canonical_domains != 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
valid_domain(arg, filename, linenum);
const char *errstr;
if (!valid_domain(arg, 1, &errstr)) {
fatal("%s line %d: %s", filename, linenum,
errstr);
}
if (!*activep || value)
continue;
if (options->num_canonical_domains >= MAX_CANON_DOMAINS)
@ -2311,11 +2287,13 @@ parse_jump(const char *s, Options *o, int active)
if (first) {
/* First argument and configuration is active */
if (parse_user_host_port(cp, &user, &host, &port) != 0)
if (parse_ssh_uri(cp, &user, &host, &port) == -1 ||
parse_user_host_port(cp, &user, &host, &port) != 0)
goto out;
} else {
/* Subsequent argument or inactive configuration */
if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
if (parse_ssh_uri(cp, NULL, NULL, NULL) == -1 ||
parse_user_host_port(cp, NULL, NULL, NULL) != 0)
goto out;
}
first = 0; /* only check syntax for subsequent hosts */
@ -2340,6 +2318,18 @@ parse_jump(const char *s, Options *o, int active)
return ret;
}
int
parse_ssh_uri(const char *uri, char **userp, char **hostp, int *portp)
{
char *path;
int r;
r = parse_uri("ssh", uri, userp, hostp, portp, &path);
if (r == 0 && path != NULL)
r = -1; /* path not allowed */
return r;
}
/* XXX the following is a near-vebatim copy from servconf.c; refactor */
static const char *
fmt_multistate_int(int val, const struct multistate *m)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.123 2017/09/03 23:33:13 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.124 2017/10/21 23:06:24 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -204,6 +204,7 @@ int read_config_file(const char *, struct passwd *, const char *,
const char *, Options *, int);
int parse_forward(struct Forward *, const char *, int, int);
int parse_jump(const char *, Options *, int);
int parse_ssh_uri(const char *, char **, char **, int *);
int default_ssh_port(void);
int option_clear_or_none(const char *);
void dump_client_config(Options *o, const char *host);

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.95 2017/06/24 06:35:24 djm Exp $
# $OpenBSD: Makefile,v 1.96 2017/10/24 19:33:32 millert Exp $
REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec
tests: prep $(REGRESS_TARGETS)
@ -19,6 +19,7 @@ distclean: clean
LTESTS= connect \
proxy-connect \
connect-privsep \
connect-uri \
proto-version \
proto-mismatch \
exit-status \
@ -42,6 +43,7 @@ LTESTS= connect \
keygen-moduli \
key-options \
scp \
scp-uri \
sftp \
sftp-chroot \
sftp-cmds \
@ -49,6 +51,7 @@ LTESTS= connect \
sftp-batch \
sftp-glob \
sftp-perm \
sftp-uri \
reconfigure \
dynamic-forward \
forwarding \

View File

@ -1,4 +1,4 @@
# $OpenBSD: agent-ptrace.sh,v 1.2 2014/02/27 21:21:25 djm Exp $
# $OpenBSD: agent-ptrace.sh,v 1.3 2015/09/11 04:55:01 djm Exp $
# Placed in the Public Domain.
tid="disallow agent ptrace attach"

View File

@ -1,5 +1,6 @@
# Public Domain
# Zev Weiss, 2016
# $OpenBSD: allow-deny-users.sh,v 1.4 2017/10/20 02:13:41 djm Exp $
tid="AllowUsers/DenyUsers"

View File

@ -1,4 +1,4 @@
# $OpenBSD: authinfo.sh,v 1.1 2017/06/24 06:35:24 djm Exp $
# $OpenBSD: authinfo.sh,v 1.2 2017/10/25 20:08:36 millert Exp $
# Placed in the Public Domain.
tid="authinfo"
@ -6,7 +6,7 @@ tid="authinfo"
# Ensure the environment variable doesn't leak when ExposeAuthInfo=no.
verbose "ExposeAuthInfo=no"
env SSH_USER_AUTH=blah ${SSH} -F $OBJ/ssh_proxy x \
'test -z "$SSH_USER_AUTH"' || fail "SSH_USER_AUTH present"
'printenv SSH_USER_AUTH >/dev/null' && fail "SSH_USER_AUTH present"
verbose "ExposeAuthInfo=yes"
echo ExposeAuthInfo=yes >> $OBJ/sshd_proxy

View File

@ -1,4 +1,4 @@
# $OpenBSD: cfgmatch.sh,v 1.10 2017/04/30 23:34:55 djm Exp $
# $OpenBSD: cfgmatch.sh,v 1.11 2017/10/04 18:50:23 djm Exp $
# Placed in the Public Domain.
tid="sshd_config match"
@ -41,7 +41,7 @@ stop_client()
cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_config
echo "Match Address 127.0.0.1" >>$OBJ/sshd_config
echo "PermitOpen 127.0.0.1:$PORT" >>$OBJ/sshd_config
echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config
grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy
echo "AuthorizedKeysFile /dev/null" >>$OBJ/sshd_proxy
@ -49,7 +49,7 @@ echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy
echo "Match user $USER" >>$OBJ/sshd_proxy
echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy
echo "Match Address 127.0.0.1" >>$OBJ/sshd_proxy
echo "PermitOpen 127.0.0.1:$PORT" >>$OBJ/sshd_proxy
echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy
start_sshd

29
regress/connect-uri.sh Normal file
View File

@ -0,0 +1,29 @@
# $OpenBSD: connect-uri.sh,v 1.1 2017/10/24 19:33:32 millert Exp $
# Placed in the Public Domain.
tid="uri connect"
# Remove Port and User from ssh_config, we want to rely on the URI
cp $OBJ/ssh_config $OBJ/ssh_config.orig
egrep -v '^ +(Port|User) +.*$' $OBJ/ssh_config.orig > $OBJ/ssh_config
start_sshd
verbose "$tid: no trailing slash"
${SSH} -F $OBJ/ssh_config "ssh://${USER}@somehost:${PORT}" true
if [ $? -ne 0 ]; then
fail "ssh connection failed"
fi
verbose "$tid: trailing slash"
${SSH} -F $OBJ/ssh_config "ssh://${USER}@somehost:${PORT}/" true
if [ $? -ne 0 ]; then
fail "ssh connection failed"
fi
verbose "$tid: with path name"
${SSH} -F $OBJ/ssh_config "ssh://${USER}@somehost:${PORT}/${DATA}" true \
> /dev/null 2>&1
if [ $? -eq 0 ]; then
fail "ssh connection succeeded, expected failure"
fi

View File

@ -1,4 +1,4 @@
# $OpenBSD: keys-command.sh,v 1.3 2015/05/21 06:40:02 djm Exp $
# $OpenBSD: keys-command.sh,v 1.4 2016/09/26 21:34:38 bluhm Exp $
# Placed in the Public Domain.
tid="authorized keys from command"

View File

@ -1,4 +1,4 @@
# $OpenBSD: keytype.sh,v 1.5 2017/03/20 22:08:06 djm Exp $
# $OpenBSD: keytype.sh,v 1.6 2017/10/30 22:01:52 djm Exp $
# Placed in the Public Domain.
tid="login with different key types"
@ -17,7 +17,7 @@ for i in `$SSH -Q key`; do
esac
done
for kt in $ktypes; do
for kt in $ktypes; do
rm -f $OBJ/key.$kt
bits=`echo ${kt} | awk -F- '{print $2}'`
type=`echo ${kt} | awk -F- '{print $1}'`
@ -27,10 +27,10 @@ for kt in $ktypes; do
done
tries="1 2 3"
for ut in $ktypes; do
for ut in $ktypes; do
htypes=$ut
#htypes=$ktypes
for ht in $htypes; do
for ht in $htypes; do
case $ht in
dsa-1024) t=ssh-dss;;
ecdsa-256) t=ecdsa-sha2-nistp256;;
@ -42,13 +42,13 @@ for ut in $ktypes; do
trace "ssh connect, userkey $ut, hostkey $ht"
(
grep -v HostKey $OBJ/sshd_proxy_bak
echo HostKey $OBJ/key.$ht
echo HostKey $OBJ/key.$ht
echo PubkeyAcceptedKeyTypes $t
echo HostKeyAlgorithms $t
) > $OBJ/sshd_proxy
(
grep -v IdentityFile $OBJ/ssh_proxy_bak
echo IdentityFile $OBJ/key.$ut
echo IdentityFile $OBJ/key.$ut
echo PubkeyAcceptedKeyTypes $t
echo HostKeyAlgorithms $t
) > $OBJ/ssh_proxy

View File

@ -30,3 +30,5 @@ Limitations: kexfuzz can't change the ordering of packets at
present. It is limited to replacing individual packets with
fuzzed variants with the same type. It really should allow
insertion, deletion on replacement of packets too.
$OpenBSD: README,v 1.3 2017/10/20 02:13:41 djm Exp $

View File

@ -1,25 +1,19 @@
# $OpenBSD: proxy-connect.sh,v 1.10 2017/04/30 23:34:55 djm Exp $
# $OpenBSD: proxy-connect.sh,v 1.11 2017/09/26 22:39:25 dtucker Exp $
# Placed in the Public Domain.
tid="proxy connect"
mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
for ps in no yes; do
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
for c in no yes; do
verbose "plain username privsep=$ps comp=$c"
opts="-oCompression=$c -F $OBJ/ssh_proxy"
SSH_CONNECTION=`${SSH} $opts 999.999.999.999 'echo $SSH_CONNECTION'`
if [ $? -ne 0 ]; then
fail "ssh proxyconnect privsep=$ps comp=$c failed"
fi
if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
fail "bad SSH_CONNECTION privsep=$ps comp=$c: " \
"$SSH_CONNECTION"
fi
done
for c in no yes; do
verbose "plain username comp=$c"
opts="-oCompression=$c -F $OBJ/ssh_proxy"
SSH_CONNECTION=`${SSH} $opts 999.999.999.999 'echo $SSH_CONNECTION'`
if [ $? -ne 0 ]; then
fail "ssh proxyconnect comp=$c failed"
fi
if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
fail "bad SSH_CONNECTION comp=$c: " \
"$SSH_CONNECTION"
fi
done
verbose "username with style"

66
regress/scp-uri.sh Normal file
View File

@ -0,0 +1,66 @@
# $OpenBSD: scp-uri.sh,v 1.1 2017/10/24 19:33:32 millert Exp $
# Placed in the Public Domain.
tid="scp-uri"
#set -x
COPY2=${OBJ}/copy2
DIR=${COPY}.dd
DIR2=${COPY}.dd2
SRC=`dirname ${SCRIPT}`
cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
chmod 755 ${OBJ}/scp-ssh-wrapper.scp
scpopts="-q -S ${OBJ}/scp-ssh-wrapper.scp"
export SCP # used in scp-ssh-wrapper.scp
scpclean() {
rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
mkdir ${DIR} ${DIR2}
}
# Remove Port and User from ssh_config, we want to rely on the URI
cp $OBJ/ssh_config $OBJ/ssh_config.orig
egrep -v '^ +(Port|User) +.*$' $OBJ/ssh_config.orig > $OBJ/ssh_config
verbose "$tid: simple copy local file to remote file"
scpclean
$SCP $scpopts ${DATA} "scp://${USER}@somehost:${PORT}/${COPY}" || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tid: simple copy remote file to local file"
scpclean
$SCP $scpopts "scp://${USER}@somehost:${PORT}/${DATA}" ${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tid: simple copy local file to remote dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts ${COPY} "scp://${USER}@somehost:${PORT}/${DIR}" || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tid: simple copy remote file to local dir"
scpclean
cp ${DATA} ${COPY}
$SCP $scpopts "scp://${USER}@somehost:${PORT}/${COPY}" ${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tid: recursive local dir to remote dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r ${DIR} "scp://${USER}@somehost:${PORT}/${DIR2}" || fail "copy failed"
diff -rN ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tid: recursive remote dir to local dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r "scp://${USER}@somehost:${PORT}/${DIR}" ${DIR2} || fail "copy failed"
diff -rN ${DIR} ${DIR2} || fail "corrupted copy"
# TODO: scp -3
scpclean
rm -f ${OBJ}/scp-ssh-wrapper.exe

63
regress/sftp-uri.sh Normal file
View File

@ -0,0 +1,63 @@
# $OpenBSD: sftp-uri.sh,v 1.1 2017/10/24 19:33:32 millert Exp $
# Placed in the Public Domain.
tid="sftp-uri"
#set -x
COPY2=${OBJ}/copy2
DIR=${COPY}.dd
DIR2=${COPY}.dd2
SRC=`dirname ${SCRIPT}`
sftpclean() {
rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
mkdir ${DIR} ${DIR2}
}
start_sshd -oForceCommand="internal-sftp -d /"
# Remove Port and User from ssh_config, we want to rely on the URI
cp $OBJ/ssh_config $OBJ/ssh_config.orig
egrep -v '^ +(Port|User) +.*$' $OBJ/ssh_config.orig > $OBJ/ssh_config
verbose "$tid: non-interactive fetch to local file"
sftpclean
${SFTP} -q -S "$SSH" -F $OBJ/ssh_config "sftp://${USER}@somehost:${PORT}/${DATA}" ${COPY} || fail "copy failed"
cmp ${DATA} ${COPY} || fail "corrupted copy"
verbose "$tid: non-interactive fetch to local dir"
sftpclean
cp ${DATA} ${COPY}
${SFTP} -q -S "$SSH" -F $OBJ/ssh_config "sftp://${USER}@somehost:${PORT}/${COPY}" ${DIR} || fail "copy failed"
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tid: put to remote directory (trailing slash)"
sftpclean
${SFTP} -q -S "$SSH" -F $OBJ/ssh_config -b /dev/stdin \
"sftp://${USER}@somehost:${PORT}/${DIR}/" > /dev/null 2>&1 << EOF
version
put ${DATA} copy
EOF
r=$?
if [ $r -ne 0 ]; then
fail "sftp failed with $r"
else
cmp ${DATA} ${DIR}/copy || fail "corrupted copy"
fi
verbose "$tid: put to remote directory (no slash)"
sftpclean
${SFTP} -q -S "$SSH" -F $OBJ/ssh_config -b /dev/stdin \
"sftp://${USER}@somehost:${PORT}/${DIR}" > /dev/null 2>&1 << EOF
version
put ${DATA} copy
EOF
r=$?
if [ $r -ne 0 ]; then
fail "sftp failed with $r"
else
cmp ${DATA} ${DIR}/copy || fail "corrupted copy"
fi
sftpclean

View File

@ -1,4 +1,4 @@
# $OpenBSD: sftp.sh,v 1.5 2013/05/17 10:28:11 dtucker Exp $
# $OpenBSD: sftp.sh,v 1.6 2017/10/30 21:59:43 djm Exp $
# Placed in the Public Domain.
tid="basic sftp put/get"
@ -22,11 +22,11 @@ for B in ${BUFFERSIZE}; do
r=$?
if [ $r -ne 0 ]; then
fail "sftp failed with $r"
else
else
cmp $DATA ${COPY}.1 || fail "corrupted copy after get"
cmp $DATA ${COPY}.2 || fail "corrupted copy after put"
fi
done
done
rm -f ${COPY}.1 ${COPY}.2
rm -f ${COPY}.1 ${COPY}.2
rm -f $SFTPCMDFILE

View File

@ -1,5 +1,5 @@
#!/bin/sh
# $OpenBSD: sshd-log-wrapper.sh,v 1.3 2013/04/07 02:16:03 dtucker Exp $
# $OpenBSD: sshd-log-wrapper.sh,v 1.4 2016/11/25 02:56:49 dtucker Exp $
# Placed in the Public Domain.
#
# simple wrapper for sshd proxy mode to catch stderr output

View File

@ -1,4 +1,4 @@
# $OpenBSD: yes-head.sh,v 1.5 2015/03/03 22:35:19 markus Exp $
# $OpenBSD: yes-head.sh,v 1.6 2017/04/30 23:34:55 djm Exp $
# Placed in the Public Domain.
tid="yes pipe head"

44
scp.1
View File

@ -8,9 +8,9 @@
.\"
.\" Created: Sun May 7 00:14:37 1995 ylo
.\"
.\" $OpenBSD: scp.1,v 1.74 2017/05/03 21:49:18 naddy Exp $
.\" $OpenBSD: scp.1,v 1.76 2017/10/25 06:19:46 jmc Exp $
.\"
.Dd $Mdocdate: May 3 2017 $
.Dd $Mdocdate: October 25 2017 $
.Dt SCP 1
.Os
.Sh NAME
@ -18,7 +18,6 @@
.Nd secure copy (remote file copy program)
.Sh SYNOPSIS
.Nm scp
.Bk -words
.Op Fl 346BCpqrv
.Op Fl c Ar cipher
.Op Fl F Ar ssh_config
@ -27,20 +26,7 @@
.Op Fl o Ar ssh_option
.Op Fl P Ar port
.Op Fl S Ar program
.Sm off
.Oo
.Op Ar user No @
.Ar host1 :
.Oc Ar file1
.Sm on
.Ar ...
.Sm off
.Oo
.Op Ar user No @
.Ar host2 :
.Oc Ar file2
.Sm on
.Ek
.Ar source ... target
.Sh DESCRIPTION
.Nm
copies files between hosts on a network.
@ -53,15 +39,33 @@ same security as
will ask for passwords or passphrases if they are needed for
authentication.
.Pp
File names may contain a user and host specification to indicate
that the file is to be copied to/from that host.
The
.Ar source
and
.Ar target
may be specified as a local pathname, a remote host with optional path
in the form
.Sm off
.Oo user @ Oc host : Op path ,
.Sm on
or a URI in the form
.Sm off
.No scp:// Oo user @ Oc host Oo : port Oc Op / path .
.Sm on
Local file names can be made explicit using absolute or relative pathnames
to avoid
.Nm
treating file names containing
.Sq :\&
as host specifiers.
Copies between two remote hosts are also permitted.
.Pp
When copying between two remote hosts, if the URI format is used, a
.Ar port
may only be specified on the
.Ar target
if the
.Fl 3
option is used.
.Pp
The options are as follows:
.Bl -tag -width Ds

197
scp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: scp.c,v 1.192 2017/05/31 09:15:42 deraadt Exp $ */
/* $OpenBSD: scp.c,v 1.193 2017/10/21 23:06:24 millert Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@ -112,6 +112,7 @@
#endif
#include "xmalloc.h"
#include "ssh.h"
#include "atomicio.h"
#include "pathnames.h"
#include "log.h"
@ -123,8 +124,8 @@ extern char *__progname;
#define COPY_BUFLEN 16384
int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);
int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);
/* Struct for addargs */
arglist args;
@ -149,6 +150,9 @@ int showprogress = 1;
*/
int throughlocal = 0;
/* Non-standard port to use for the ssh connection or -1. */
int sshport = -1;
/* This is the program to execute for the secured connection. ("ssh" or -S) */
char *ssh_program = _PATH_SSH_PROGRAM;
@ -252,7 +256,7 @@ do_local_cmd(arglist *a)
*/
int
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
{
int pin[2], pout[2], reserved[2];
@ -262,6 +266,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
if (port == -1)
port = sshport;
/*
* Reserve two descriptors so that the real pipes won't get
* descriptors 0 and 1 because that will screw up dup2 below.
@ -313,6 +320,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
close(pout[1]);
replacearg(&args, 0, "%s", ssh_program);
if (port != -1) {
addargs(&args, "-p");
addargs(&args, "%d", port);
}
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
@ -344,7 +355,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
* This way the input and output of two commands can be connected.
*/
int
do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
{
pid_t pid;
int status;
@ -355,6 +366,9 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
ssh_program, host,
remuser ? remuser : "(unspecified)", cmd);
if (port == -1)
port = sshport;
/* Fork a child to execute the command on the remote host using ssh. */
#ifdef WINDOWS
/* generate command line and spawn_child */
@ -377,6 +391,10 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
dup2(fdout, 1);
replacearg(&args, 0, "%s", ssh_program);
if (port != -1) {
addargs(&args, "-p");
addargs(&args, "%d", port);
}
if (remuser != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", remuser);
@ -421,14 +439,14 @@ void rsource(char *, struct stat *);
void sink(int, char *[]);
void source(int, char *[]);
void tolocal(int, char *[]);
void toremote(char *, int, char *[]);
void toremote(int, char *[]);
void usage(void);
int
main(int argc, char **argv)
{
int ch, fflag, tflag, status, n;
char *targ, **newargv;
char **newargv;
const char *errstr;
extern char *optarg;
extern int optind;
@ -484,10 +502,9 @@ main(int argc, char **argv)
addargs(&args, "%s", optarg);
break;
case 'P':
addargs(&remote_remote_args, "-p");
addargs(&remote_remote_args, "%s", optarg);
addargs(&args, "-p");
addargs(&args, "%s", optarg);
sshport = a2port(optarg);
if (sshport <= 0)
fatal("bad port \"%s\"\n", optarg);
break;
case 'B':
addargs(&remote_remote_args, "-oBatchmode=yes");
@ -604,8 +621,8 @@ main(int argc, char **argv)
(void) signal(SIGPIPE, lostconn);
if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
toremote(targ, argc, argv);
if (colon(argv[argc - 1])) /* Dest is remote host. */
toremote(argc, argv);
else {
if (targetshouldbedirectory)
verifydir(argv[argc - 1]);
@ -661,71 +678,65 @@ do_times(int fd, int verb, const struct stat *sb)
}
void
toremote(char *targ, int argc, char **argv)
toremote(int argc, char **argv)
{
char *bp, *host, *src, *suser, *thost, *tuser, *arg;
char *suser = NULL, *host = NULL, *src = NULL;
char *bp, *tuser, *thost, *targ;
int sport = -1, tport = -1;
arglist alist;
int i;
int i, r;
u_int j;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
*targ++ = 0;
if (*targ == 0)
targ = ".";
arg = xstrdup(argv[argc - 1]);
if ((thost = strrchr(arg, '@'))) {
/* user@host */
*thost++ = 0;
tuser = arg;
if (*tuser == '\0')
tuser = NULL;
} else {
thost = arg;
tuser = NULL;
}
if (tuser != NULL && !okname(tuser)) {
free(arg);
return;
/* Parse target */
r = parse_uri("scp", argv[argc - 1], &tuser, &thost, &tport, &targ);
if (r == -1)
goto out; /* invalid URI */
if (r != 0) {
if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
&targ) == -1)
goto out;
}
if (tuser != NULL && !okname(tuser))
goto out;
/* Parse source files */
for (i = 0; i < argc - 1; i++) {
src = colon(argv[i]);
if (src && throughlocal) { /* extended remote to remote */
*src++ = 0;
if (*src == 0)
src = ".";
host = strrchr(argv[i], '@');
if (host) {
*host++ = 0;
host = cleanhostname(host);
suser = argv[i];
if (*suser == '\0')
suser = pwd->pw_name;
else if (!okname(suser))
continue;
} else {
host = cleanhostname(argv[i]);
suser = NULL;
}
free(suser);
free(host);
free(src);
r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
if (r == -1)
continue; /* invalid URI */
if (r != 0)
parse_user_host_path(argv[i], &suser, &host, &src);
if (suser != NULL && !okname(suser)) {
++errs;
continue;
}
if (host && throughlocal) { /* extended remote to remote */
xasprintf(&bp, "%s -f %s%s", cmd,
*src == '-' ? "-- " : "", src);
if (do_cmd(host, suser, bp, &remin, &remout) < 0)
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
exit(1);
free(bp);
host = cleanhostname(thost);
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
if (do_cmd2(host, tuser, bp, remin, remout) < 0)
if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0)
exit(1);
free(bp);
(void) close(remin);
(void) close(remout);
remin = remout = -1;
} else if (src) { /* standard remote to remote */
} else if (host) { /* standard remote to remote */
if (tport != -1 && tport != SSH_DEFAULT_PORT) {
/* This would require the remote support URIs */
fatal("target port not supported with two "
"remote hosts without the -3 option");
}
freeargs(&alist);
addargs(&alist, "%s", ssh_program);
addargs(&alist, "-x");
@ -735,23 +746,14 @@ toremote(char *targ, int argc, char **argv)
addargs(&alist, "%s",
remote_remote_args.list[j]);
}
*src++ = 0;
if (*src == 0)
src = ".";
host = strrchr(argv[i], '@');
if (host) {
*host++ = 0;
host = cleanhostname(host);
suser = argv[i];
if (*suser == '\0')
suser = pwd->pw_name;
else if (!okname(suser))
continue;
if (sport != -1) {
addargs(&alist, "-p");
addargs(&alist, "%d", sport);
}
if (suser) {
addargs(&alist, "-l");
addargs(&alist, "%s", suser);
} else {
host = cleanhostname(argv[i]);
}
addargs(&alist, "--");
addargs(&alist, "%s", host);
@ -766,8 +768,7 @@ toremote(char *targ, int argc, char **argv)
if (remin == -1) {
xasprintf(&bp, "%s -t %s%s", cmd,
*targ == '-' ? "-- " : "", targ);
host = cleanhostname(thost);
if (do_cmd(host, tuser, bp, &remin,
if (do_cmd(thost, tuser, tport, bp, &remin,
&remout) < 0)
exit(1);
if (response() < 0)
@ -777,21 +778,41 @@ toremote(char *targ, int argc, char **argv)
source(1, argv + i);
}
}
free(arg);
out:
free(tuser);
free(thost);
free(targ);
free(suser);
free(host);
free(src);
}
void
tolocal(int argc, char **argv)
{
char *bp, *host, *src, *suser;
char *bp, *host = NULL, *src = NULL, *suser = NULL;
arglist alist;
int i;
int i, r, sport = -1;
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
for (i = 0; i < argc - 1; i++) {
if (!(src = colon(argv[i]))) { /* Local to local. */
free(suser);
free(host);
free(src);
r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
if (r == -1) {
++errs;
continue;
}
if (r != 0)
parse_user_host_path(argv[i], &suser, &host, &src);
if (suser != NULL && !okname(suser)) {
++errs;
continue;
}
if (!host) { /* Local to local. */
freeargs(&alist);
#ifdef WINDOWS
#define _PATH_XCOPY "xcopy"
@ -841,22 +862,10 @@ tolocal(int argc, char **argv)
++errs;
continue;
}
*src++ = 0;
if (*src == 0)
src = ".";
if ((host = strrchr(argv[i], '@')) == NULL) {
host = argv[i];
suser = NULL;
} else {
*host++ = 0;
suser = argv[i];
if (*suser == '\0')
suser = pwd->pw_name;
}
host = cleanhostname(host);
/* Remote to local. */
xasprintf(&bp, "%s -f %s%s",
cmd, *src == '-' ? "-- " : "", src);
if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
free(bp);
++errs;
continue;
@ -866,6 +875,9 @@ tolocal(int argc, char **argv)
(void) close(remin);
remin = remout = -1;
}
free(suser);
free(host);
free(src);
}
void
@ -1387,8 +1399,7 @@ usage(void)
{
(void) fprintf(stderr,
"usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-l limit] [-o ssh_option] [-P port] [-S program]\n"
" [[user@]host1:]file1 ... [[user@]host2:]file2\n");
" [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
exit(1);
}

View File

@ -1,5 +1,5 @@
/* $OpenBSD: servconf.c,v 1.312 2017/10/02 19:33:20 djm Exp $ */
/* $OpenBSD: servconf.c,v 1.320 2017/11/03 05:18:44 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -15,10 +15,16 @@
#include <sys/types.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#ifdef HAVE_NET_ROUTE_H
#include <net/route.h>
#endif
#include <ctype.h>
#include <netdb.h>
@ -58,8 +64,10 @@
#include "myproposal.h"
#include "digest.h"
static void add_listen_addr(ServerOptions *, char *, int);
static void add_one_listen_addr(ServerOptions *, char *, int);
static void add_listen_addr(ServerOptions *, const char *,
const char *, int);
static void add_one_listen_addr(ServerOptions *, const char *,
const char *, int);
/* Use of privilege separation or not */
extern int use_privsep;
@ -81,7 +89,9 @@ initialize_server_options(ServerOptions *options)
options->queued_listen_addrs = NULL;
options->num_queued_listens = 0;
options->listen_addrs = NULL;
options->num_listen_addrs = 0;
options->address_family = -1;
options->routing_domain = NULL;
options->num_host_key_files = 0;
options->num_host_cert_files = 0;
options->host_key_agent = NULL;
@ -188,10 +198,45 @@ assemble_algorithms(ServerOptions *o)
fatal("kex_assemble_names failed");
}
static void
array_append(const char *file, const int line, const char *directive,
char ***array, u_int *lp, const char *s)
{
if (*lp >= INT_MAX)
fatal("%s line %d: Too many %s entries", file, line, directive);
*array = xrecallocarray(*array, *lp, *lp + 1, sizeof(**array));
(*array)[*lp] = xstrdup(s);
(*lp)++;
}
void
servconf_add_hostkey(const char *file, const int line,
ServerOptions *options, const char *path)
{
char *apath = derelativise_path(path);
array_append(file, line, "HostKey",
&options->host_key_files, &options->num_host_key_files, apath);
free(apath);
}
void
servconf_add_hostcert(const char *file, const int line,
ServerOptions *options, const char *path)
{
char *apath = derelativise_path(path);
array_append(file, line, "HostCertificate",
&options->host_cert_files, &options->num_host_cert_files, apath);
free(apath);
}
void
fill_default_server_options(ServerOptions *options)
{
int i;
u_int i;
/* Portable-specific options */
if (options->use_pam == -1)
@ -200,16 +245,16 @@ fill_default_server_options(ServerOptions *options)
/* Standard Options */
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
options->host_key_files[options->num_host_key_files++] =
_PATH_HOST_RSA_KEY_FILE;
options->host_key_files[options->num_host_key_files++] =
_PATH_HOST_DSA_KEY_FILE;
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_RSA_KEY_FILE);
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_DSA_KEY_FILE);
#ifdef OPENSSL_HAS_ECC
options->host_key_files[options->num_host_key_files++] =
_PATH_HOST_ECDSA_KEY_FILE;
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_ECDSA_KEY_FILE);
#endif
options->host_key_files[options->num_host_key_files++] =
_PATH_HOST_ED25519_KEY_FILE;
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_ED25519_KEY_FILE);
}
/* No certificates by default */
if (options->num_ports == 0)
@ -217,7 +262,7 @@ fill_default_server_options(ServerOptions *options)
if (options->address_family == -1)
options->address_family = AF_UNSPEC;
if (options->listen_addrs == NULL)
add_listen_addr(options, NULL, 0);
add_listen_addr(options, NULL, NULL, 0);
if (options->pid_file == NULL)
options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
if (options->login_grace_time == -1)
@ -313,10 +358,14 @@ fill_default_server_options(ServerOptions *options)
if (options->client_alive_count_max == -1)
options->client_alive_count_max = 3;
if (options->num_authkeys_files == 0) {
options->authorized_keys_files[options->num_authkeys_files++] =
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
options->authorized_keys_files[options->num_authkeys_files++] =
xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
array_append("[default]", 0, "AuthorizedKeysFiles",
&options->authorized_keys_files,
&options->num_authkeys_files,
_PATH_SSH_USER_PERMITTED_KEYS);
array_append("[default]", 0, "AuthorizedKeysFiles",
&options->authorized_keys_files,
&options->num_authkeys_files,
_PATH_SSH_USER_PERMITTED_KEYS2);
}
if (options->permit_tun == -1)
options->permit_tun = SSH_TUNMODE_NO;
@ -358,6 +407,7 @@ fill_default_server_options(ServerOptions *options)
CLEAR_ON_NONE(options->authorized_principals_file);
CLEAR_ON_NONE(options->adm_forced_command);
CLEAR_ON_NONE(options->chroot_directory);
CLEAR_ON_NONE(options->routing_domain);
for (i = 0; i < options->num_host_key_files; i++)
CLEAR_ON_NONE(options->host_key_files[i]);
for (i = 0; i < options->num_host_cert_files; i++)
@ -421,7 +471,7 @@ typedef enum {
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo,
sExposeAuthInfo, sRDomain,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
@ -566,6 +616,7 @@ static struct {
{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
{ "disableforwarding", sDisableForwarding, SSHCFG_ALL },
{ "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
{ "rdomain", sRDomain, SSHCFG_ALL },
{ NULL, sBadOption, 0 }
};
@ -625,23 +676,51 @@ derelativise_path(const char *path)
}
static void
add_listen_addr(ServerOptions *options, char *addr, int port)
add_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
u_int i;
if (port == 0)
for (i = 0; i < options->num_ports; i++)
add_one_listen_addr(options, addr, options->ports[i]);
else
add_one_listen_addr(options, addr, port);
if (port > 0)
add_one_listen_addr(options, addr, rdomain, port);
else {
for (i = 0; i < options->num_ports; i++) {
add_one_listen_addr(options, addr, rdomain,
options->ports[i]);
}
}
}
static void
add_one_listen_addr(ServerOptions *options, char *addr, int port)
add_one_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
u_int i;
/* Find listen_addrs entry for this rdomain */
for (i = 0; i < options->num_listen_addrs; i++) {
if (rdomain == NULL && options->listen_addrs[i].rdomain == NULL)
break;
if (rdomain == NULL || options->listen_addrs[i].rdomain == NULL)
continue;
if (strcmp(rdomain, options->listen_addrs[i].rdomain) == 0)
break;
}
if (i >= options->num_listen_addrs) {
/* No entry for this rdomain; allocate one */
if (i >= INT_MAX)
fatal("%s: too many listen addresses", __func__);
options->listen_addrs = xrecallocarray(options->listen_addrs,
options->num_listen_addrs, options->num_listen_addrs + 1,
sizeof(*options->listen_addrs));
i = options->num_listen_addrs++;
if (rdomain != NULL)
options->listen_addrs[i].rdomain = xstrdup(rdomain);
}
/* options->listen_addrs[i] points to the addresses for this rdomain */
memset(&hints, 0, sizeof(hints));
hints.ai_family = options->address_family;
@ -654,8 +733,44 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
ssh_gai_strerror(gaierr));
for (ai = aitop; ai->ai_next; ai = ai->ai_next)
;
ai->ai_next = options->listen_addrs;
options->listen_addrs = aitop;
ai->ai_next = options->listen_addrs[i].addrs;
options->listen_addrs[i].addrs = aitop;
}
/* Returns nonzero if the routing domain name is valid */
static int
valid_rdomain(const char *name)
{
#if defined(HAVE_SYS_VALID_RDOMAIN)
return sys_valid_rdomain(name);
#elif defined(__OpenBSD__)
const char *errstr;
long long num;
struct rt_tableinfo info;
int mib[6];
size_t miblen = sizeof(mib);
if (name == NULL)
return 1;
num = strtonum(name, 0, 255, &errstr);
if (errstr != NULL)
return 0;
/* Check whether the table actually exists */
memset(mib, 0, sizeof(mib));
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[4] = NET_RT_TABLE;
mib[5] = (int)num;
if (sysctl(mib, 6, &info, &miblen, NULL, 0) == -1)
return 0;
return 1;
#else /* defined(__OpenBSD__) */
error("Routing domains are not supported on this platform");
return 0;
#endif
}
/*
@ -663,18 +778,19 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
* and AddressFamily options.
*/
static void
queue_listen_addr(ServerOptions *options, char *addr, int port)
queue_listen_addr(ServerOptions *options, const char *addr,
const char *rdomain, int port)
{
options->queued_listen_addrs = xreallocarray(
options->queued_listen_addrs, options->num_queued_listens + 1,
sizeof(addr));
options->queued_listen_ports = xreallocarray(
options->queued_listen_ports, options->num_queued_listens + 1,
sizeof(port));
options->queued_listen_addrs[options->num_queued_listens] =
xstrdup(addr);
options->queued_listen_ports[options->num_queued_listens] = port;
options->num_queued_listens++;
struct queued_listenaddr *qla;
options->queued_listen_addrs = xrecallocarray(
options->queued_listen_addrs,
options->num_queued_listens, options->num_queued_listens + 1,
sizeof(*options->queued_listen_addrs));
qla = &options->queued_listen_addrs[options->num_queued_listens++];
qla->addr = xstrdup(addr);
qla->port = port;
qla->rdomain = rdomain == NULL ? NULL : xstrdup(rdomain);
}
/*
@ -684,6 +800,7 @@ static void
process_queued_listen_addrs(ServerOptions *options)
{
u_int i;
struct queued_listenaddr *qla;
if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
@ -691,15 +808,13 @@ process_queued_listen_addrs(ServerOptions *options)
options->address_family = AF_UNSPEC;
for (i = 0; i < options->num_queued_listens; i++) {
add_listen_addr(options, options->queued_listen_addrs[i],
options->queued_listen_ports[i]);
free(options->queued_listen_addrs[i]);
options->queued_listen_addrs[i] = NULL;
qla = &options->queued_listen_addrs[i];
add_listen_addr(options, qla->addr, qla->rdomain, qla->port);
free(qla->addr);
free(qla->rdomain);
}
free(options->queued_listen_addrs);
options->queued_listen_addrs = NULL;
free(options->queued_listen_ports);
options->queued_listen_ports = NULL;
options->num_queued_listens = 0;
}
@ -753,6 +868,7 @@ get_connection_info(int populate, int use_dns)
ci.address = ssh_remote_ipaddr(ssh);
ci.laddress = ssh_local_ipaddr(ssh);
ci.lport = ssh_local_port(ssh);
ci.rdomain = ssh_packet_rdomain_in(ssh);
return &ci;
}
@ -817,6 +933,13 @@ out:
return result;
}
static void
match_test_missing_fatal(const char *criteria, const char *attrib)
{
fatal("'Match %s' in configuration but '%s' not in connection "
"test specification.", criteria, attrib);
}
/*
* All of the attributes on a single Match line are ANDed together, so we need
* to check every attribute and set the result to zero if any attribute does
@ -854,20 +977,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci)
return -1;
}
if (strcasecmp(attrib, "user") == 0) {
if (ci == NULL || ci->user == NULL) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->user == NULL)
match_test_missing_fatal("User", "user");
if (match_pattern_list(ci->user, arg, 0) != 1)
result = 0;
else
debug("user %.100s matched 'User %.100s' at "
"line %d", ci->user, arg, line);
} else if (strcasecmp(attrib, "group") == 0) {
if (ci == NULL || ci->user == NULL) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->user == NULL)
match_test_missing_fatal("Group", "user");
switch (match_cfg_line_group(arg, line, ci->user)) {
case -1:
return -1;
@ -875,20 +1002,24 @@ match_cfg_line(char **condition, int line, struct connection_info *ci)
result = 0;
}
} else if (strcasecmp(attrib, "host") == 0) {
if (ci == NULL || ci->host == NULL) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->host == NULL)
match_test_missing_fatal("Host", "host");
if (match_hostname(ci->host, arg) != 1)
result = 0;
else
debug("connection from %.100s matched 'Host "
"%.100s' at line %d", ci->host, arg, line);
} else if (strcasecmp(attrib, "address") == 0) {
if (ci == NULL || ci->address == NULL) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->address == NULL)
match_test_missing_fatal("Address", "addr");
switch (addr_match_list(ci->address, arg)) {
case 1:
debug("connection from %.100s matched 'Address "
@ -902,10 +1033,13 @@ match_cfg_line(char **condition, int line, struct connection_info *ci)
return -1;
}
} else if (strcasecmp(attrib, "localaddress") == 0){
if (ci == NULL || ci->laddress == NULL) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->laddress == NULL)
match_test_missing_fatal("LocalAddress",
"laddr");
switch (addr_match_list(ci->laddress, arg)) {
case 1:
debug("connection from %.100s matched "
@ -925,10 +1059,12 @@ match_cfg_line(char **condition, int line, struct connection_info *ci)
arg);
return -1;
}
if (ci == NULL || ci->lport == 0) {
if (ci == NULL) {
result = 0;
continue;
}
if (ci->lport == 0)
match_test_missing_fatal("LocalPort", "lport");
/* TODO support port lists */
if (port == ci->lport)
debug("connection from %.100s matched "
@ -936,6 +1072,16 @@ match_cfg_line(char **condition, int line, struct connection_info *ci)
ci->laddress, port, line);
else
result = 0;
} else if (strcasecmp(attrib, "rdomain") == 0) {
if (ci == NULL || ci->rdomain == NULL) {
result = 0;
continue;
}
if (match_pattern_list(ci->rdomain, arg, 0) != 1)
result = 0;
else
debug("user %.100s matched 'RDomain %.100s' at "
"line %d", ci->rdomain, arg, line);
} else {
error("Unsupported Match attribute %s", attrib);
return -1;
@ -958,6 +1104,11 @@ struct multistate {
char *key;
int value;
};
static const struct multistate multistate_flag[] = {
{ "yes", 1 },
{ "no", 0 },
{ NULL, -1 }
};
static const struct multistate multistate_addressfamily[] = {
{ "inet", AF_INET },
{ "inet6", AF_INET6 },
@ -1094,20 +1245,33 @@ process_server_config_line(ServerOptions *options, char *line,
/* check for bare IPv6 address: no "[]" and 2 or more ":" */
if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
&& strchr(p+1, ':') != NULL) {
queue_listen_addr(options, arg, 0);
break;
}
p = hpdelim(&arg);
if (p == NULL)
fatal("%s line %d: bad address:port usage",
filename, linenum);
p = cleanhostname(p);
if (arg == NULL)
port = 0;
else if ((port = a2port(arg)) <= 0)
fatal("%s line %d: bad port number", filename, linenum);
p = arg;
} else {
p = hpdelim(&arg);
if (p == NULL)
fatal("%s line %d: bad address:port usage",
filename, linenum);
p = cleanhostname(p);
if (arg == NULL)
port = 0;
else if ((port = a2port(arg)) <= 0)
fatal("%s line %d: bad port number",
filename, linenum);
}
/* Optional routing table */
arg2 = NULL;
if ((arg = strdelim(&cp)) != NULL) {
if (strcmp(arg, "rdomain") != 0 ||
(arg2 = strdelim(&cp)) == NULL)
fatal("%s line %d: bad ListenAddress syntax",
filename, linenum);
if (!valid_rdomain(arg2))
fatal("%s line %d: bad routing domain",
filename, linenum);
}
queue_listen_addr(options, p, port);
queue_listen_addr(options, p, arg2, port);
break;
@ -1134,22 +1298,12 @@ process_server_config_line(ServerOptions *options, char *line,
break;
case sHostKeyFile:
intptr = &options->num_host_key_files;
if (*intptr >= MAX_HOSTKEYS)
fatal("%s line %d: too many host keys specified (max %d).",
filename, linenum, MAX_HOSTKEYS);
charptr = &options->host_key_files[*intptr];
parse_filename:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL) {
*charptr = derelativise_path(arg);
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
if (*activep)
servconf_add_hostkey(filename, linenum, options, arg);
break;
case sHostKeyAgent:
@ -1164,17 +1318,28 @@ process_server_config_line(ServerOptions *options, char *line,
break;
case sHostCertificate:
intptr = &options->num_host_cert_files;
if (*intptr >= MAX_HOSTKEYS)
fatal("%s line %d: too many host certificates "
"specified (max %d).", filename, linenum,
MAX_HOSTCERTS);
charptr = &options->host_cert_files[*intptr];
goto parse_filename;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep)
servconf_add_hostcert(filename, linenum, options, arg);
break;
case sPidFile:
charptr = &options->pid_file;
goto parse_filename;
parse_filename:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing file name.",
filename, linenum);
if (*activep && *charptr == NULL) {
*charptr = derelativise_path(arg);
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break;
case sPermitRootLogin:
intptr = &options->permit_root_login;
@ -1184,21 +1349,8 @@ process_server_config_line(ServerOptions *options, char *line,
case sIgnoreRhosts:
intptr = &options->ignore_rhosts;
parse_flag:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: missing yes/no argument.",
filename, linenum);
value = 0; /* silence compiler */
if (strcmp(arg, "yes") == 0)
value = 1;
else if (strcmp(arg, "no") == 0)
value = 0;
else
fatal("%s line %d: Bad yes/no argument: %s",
filename, linenum, arg);
if (*activep && *intptr == -1)
*intptr = value;
break;
multistate_ptr = multistate_flag;
goto parse_multistate;
case sIgnoreUserKnownHosts:
intptr = &options->ignore_user_known_hosts;
@ -1418,55 +1570,47 @@ process_server_config_line(ServerOptions *options, char *line,
case sAllowUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_users >= MAX_ALLOW_USERS)
fatal("%s line %d: too many allow users.",
filename, linenum);
if (match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid AllowUsers pattern: "
"\"%.100s\"", filename, linenum, arg);
if (!*activep)
continue;
options->allow_users[options->num_allow_users++] =
xstrdup(arg);
array_append(filename, linenum, "AllowUsers",
&options->allow_users, &options->num_allow_users,
arg);
}
break;
case sDenyUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_users >= MAX_DENY_USERS)
fatal("%s line %d: too many deny users.",
filename, linenum);
if (match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid DenyUsers pattern: "
"\"%.100s\"", filename, linenum, arg);
if (!*activep)
continue;
options->deny_users[options->num_deny_users++] =
xstrdup(arg);
array_append(filename, linenum, "DenyUsers",
&options->deny_users, &options->num_deny_users,
arg);
}
break;
case sAllowGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
fatal("%s line %d: too many allow groups.",
filename, linenum);
if (!*activep)
continue;
options->allow_groups[options->num_allow_groups++] =
xstrdup(arg);
array_append(filename, linenum, "AllowGroups",
&options->allow_groups, &options->num_allow_groups,
arg);
}
break;
case sDenyGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_groups >= MAX_DENY_GROUPS)
fatal("%s line %d: too many deny groups.",
filename, linenum);
if (!*activep)
continue;
options->deny_groups[options->num_deny_groups++] =
xstrdup(arg);
array_append(filename, linenum, "DenyGroups",
&options->deny_groups, &options->num_deny_groups,
arg);
}
break;
@ -1585,14 +1729,12 @@ process_server_config_line(ServerOptions *options, char *line,
case sAuthorizedKeysFile:
if (*activep && options->num_authkeys_files == 0) {
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_authkeys_files >=
MAX_AUTHKEYS_FILES)
fatal("%s line %d: "
"too many authorized keys files.",
filename, linenum);
options->authorized_keys_files[
options->num_authkeys_files++] =
tilde_expand_filename(arg, getuid());
arg = tilde_expand_filename(arg, getuid());
array_append(filename, linenum,
"AuthorizedKeysFile",
&options->authorized_keys_files,
&options->num_authkeys_files, arg);
free(arg);
}
}
return 0;
@ -1624,13 +1766,11 @@ process_server_config_line(ServerOptions *options, char *line,
if (strchr(arg, '=') != NULL)
fatal("%s line %d: Invalid environment name.",
filename, linenum);
if (options->num_accept_env >= MAX_ACCEPT_ENV)
fatal("%s line %d: too many allow env.",
filename, linenum);
if (!*activep)
continue;
options->accept_env[options->num_accept_env++] =
xstrdup(arg);
array_append(filename, linenum, "AcceptEnv",
&options->accept_env, &options->num_accept_env,
arg);
}
break;
@ -1669,9 +1809,9 @@ process_server_config_line(ServerOptions *options, char *line,
if (!arg || *arg == '\0')
fatal("%s line %d: missing PermitOpen specification",
filename, linenum);
i = options->num_permitted_opens; /* modified later */
value = options->num_permitted_opens; /* modified later */
if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
if (*activep && i == 0) {
if (*activep && value == 0) {
options->num_permitted_opens = 1;
options->permitted_opens = xcalloc(1,
sizeof(*options->permitted_opens));
@ -1689,16 +1829,13 @@ process_server_config_line(ServerOptions *options, char *line,
if (arg == NULL || ((port = permitopen_port(arg)) < 0))
fatal("%s line %d: bad port number in "
"PermitOpen", filename, linenum);
if (*activep && i == 0) {
options->permitted_opens = xrecallocarray(
options->permitted_opens,
options->num_permitted_opens,
options->num_permitted_opens + 1,
sizeof(*options->permitted_opens));
i = options->num_permitted_opens++;
options->permitted_opens[i] = arg2;
} else
free(arg2);
if (*activep && value == 0) {
array_append(filename, linenum,
"PermitOpen",
&options->permitted_opens,
&options->num_permitted_opens, arg2);
}
free(arg2);
}
break;
@ -1821,11 +1958,6 @@ process_server_config_line(ServerOptions *options, char *line,
value = 0; /* seen "any" pseudo-method */
value2 = 0; /* sucessfully parsed any method */
while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_auth_methods >=
MAX_AUTH_METHODS)
fatal("%s line %d: "
"too many authentication methods.",
filename, linenum);
if (strcmp(arg, "any") == 0) {
if (options->num_auth_methods > 0) {
fatal("%s line %d: \"any\" "
@ -1846,8 +1978,10 @@ process_server_config_line(ServerOptions *options, char *line,
value2 = 1;
if (!*activep)
continue;
options->auth_methods[
options->num_auth_methods++] = xstrdup(arg);
array_append(filename, linenum,
"AuthenticationMethods",
&options->auth_methods,
&options->num_auth_methods, arg);
}
if (value2 == 0) {
fatal("%s line %d: no AuthenticationMethods "
@ -1889,6 +2023,19 @@ process_server_config_line(ServerOptions *options, char *line,
intptr = &options->expose_userauth_info;
goto parse_flag;
case sRDomain:
charptr = &options->routing_domain;
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.",
filename, linenum);
if (strcasecmp(arg, "none") != 0 && strcmp(arg, "%D") != 0 &&
!valid_rdomain(arg))
fatal("%s line %d: bad routing domain",
filename, linenum);
if (*activep && *charptr == NULL)
*charptr = xstrdup(arg);
case sDeprecated:
case sIgnore:
case sUnsupported:
@ -1969,6 +2116,8 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec)
ci->user = xstrdup(p + 5);
} else if (strncmp(p, "laddr=", 6) == 0) {
ci->laddress = xstrdup(p + 6);
} else if (strncmp(p, "rdomain=", 8) == 0) {
ci->rdomain = xstrdup(p + 8);
} else if (strncmp(p, "lport=", 6) == 0) {
ci->lport = a2port(p + 6);
if (ci->lport == -1) {
@ -1985,19 +2134,6 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec)
return 0;
}
/*
* returns 1 for a complete spec, 0 for partial spec and -1 for an
* empty spec.
*/
int server_match_spec_complete(struct connection_info *ci)
{
if (ci->user && ci->host && ci->address)
return 1; /* complete */
if (!ci->user && !ci->host && !ci->address)
return -1; /* empty */
return 0; /* partial */
}
/*
* Copy any supported values that are set.
*
@ -2063,17 +2199,16 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
dst->n = src->n; \
} \
} while(0)
#define M_CP_STRARRAYOPT(n, num_n) do {\
if (src->num_n != 0) { \
for (dst->num_n = 0; dst->num_n < src->num_n; dst->num_n++) \
dst->n[dst->num_n] = xstrdup(src->n[dst->num_n]); \
} \
} while(0)
#define M_CP_STRARRAYOPT_ALLOC(n, num_n) do { \
if (src->num_n != 0) { \
dst->n = xcalloc(src->num_n, sizeof(*dst->n)); \
M_CP_STRARRAYOPT(n, num_n); \
dst->num_n = src->num_n; \
#define M_CP_STRARRAYOPT(s, num_s) do {\
u_int i; \
if (src->num_s != 0) { \
for (i = 0; i < dst->num_s; i++) \
free(dst->s[i]); \
free(dst->s); \
dst->s = xcalloc(src->num_s, sizeof(*dst->s)); \
for (i = 0; i < src->num_s; i++) \
dst->s[i] = xstrdup(src->s[i]); \
dst->num_s = src->num_s; \
} \
} while(0)
@ -2106,7 +2241,6 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
#undef M_CP_INTOPT
#undef M_CP_STROPT
#undef M_CP_STRARRAYOPT
#undef M_CP_STRARRAYOPT_ALLOC
void
parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
@ -2263,45 +2397,61 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
printf("\n");
}
void
dump_config(ServerOptions *o)
static char *
format_listen_addrs(struct listenaddr *la)
{
u_int i;
int ret;
int r;
struct addrinfo *ai;
char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
char addr[NI_MAXHOST], port[NI_MAXSERV];
char *laddr1 = xstrdup(""), *laddr2 = NULL;
/* these are usually at the top of the config */
for (i = 0; i < o->num_ports; i++)
printf("port %d\n", o->ports[i]);
dump_cfg_fmtint(sAddressFamily, o->address_family);
/*
* ListenAddress must be after Port. add_one_listen_addr pushes
* addresses onto a stack, so to maintain ordering we need to
* print these in reverse order.
*/
for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
for (ai = la->addrs; ai; ai = ai->ai_next) {
if ((r = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
sizeof(addr), port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
error("getnameinfo failed: %.100s",
(ret != EAI_SYSTEM) ? gai_strerror(ret) :
strerror(errno));
} else {
laddr2 = laddr1;
if (ai->ai_family == AF_INET6)
xasprintf(&laddr1, "listenaddress [%s]:%s\n%s",
addr, port, laddr2);
else
xasprintf(&laddr1, "listenaddress %s:%s\n%s",
addr, port, laddr2);
free(laddr2);
error("getnameinfo: %.100s", ssh_gai_strerror(r));
continue;
}
laddr2 = laddr1;
if (ai->ai_family == AF_INET6) {
xasprintf(&laddr1, "listenaddress [%s]:%s%s%s\n%s",
addr, port,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain,
laddr2);
} else {
xasprintf(&laddr1, "listenaddress %s:%s%s%s\n%s",
addr, port,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain,
laddr2);
}
free(laddr2);
}
return laddr1;
}
void
dump_config(ServerOptions *o)
{
char *s;
u_int i;
/* these are usually at the top of the config */
for (i = 0; i < o->num_ports; i++)
printf("port %d\n", o->ports[i]);
dump_cfg_fmtint(sAddressFamily, o->address_family);
for (i = 0; i < o->num_listen_addrs; i++) {
s = format_listen_addrs(&o->listen_addrs[i]);
printf("%s", s);
free(s);
}
printf("%s", laddr1);
free(laddr1);
/* integer arguments */
#ifdef USE_PAM
@ -2390,6 +2540,7 @@ dump_config(ServerOptions *o)
o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ?
o->pubkey_key_types : KEX_DEFAULT_PK_ALG);
dump_cfg_string(sRDomain, o->routing_domain);
/* string arguments requiring a lookup */
dump_cfg_string(sLogLevel, log_level_name(o->log_level));
@ -2418,11 +2569,13 @@ dump_config(ServerOptions *o)
printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
o->max_startups_rate, o->max_startups);
for (i = 0; tunmode_desc[i].val != -1; i++)
s = NULL;
for (i = 0; tunmode_desc[i].val != -1; i++) {
if (tunmode_desc[i].val == o->permit_tun) {
s = tunmode_desc[i].text;
break;
}
}
dump_cfg_string(sPermitTunnel, s);
printf("ipqos %s ", iptos2str(o->ip_qos_interactive));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.126 2017/10/02 19:33:20 djm Exp $ */
/* $OpenBSD: servconf.h,v 1.130 2017/10/25 00:19:47 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -18,17 +18,7 @@
#define MAX_PORTS 256 /* Max # ports. */
#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
#define MAX_DENY_USERS 256 /* Max # users on deny list. */
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
#define MAX_HOSTKEYS 256 /* Max # hostkeys. */
#define MAX_HOSTCERTS 256 /* Max # host certificates. */
#define MAX_ACCEPT_ENV 256 /* Max # of env vars. */
#define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */
#define MAX_AUTHKEYS_FILES 256 /* Max # of authorized_keys files. */
#define MAX_AUTH_METHODS 256 /* Max # of AuthenticationMethods. */
/* permit_root_login */
#define PERMIT_NOT_SET -1
@ -61,21 +51,42 @@
struct ssh;
struct fwd_perm_list;
/*
* Used to store addresses from ListenAddr directives. These may be
* incomplete, as they may specify addresses that need to be merged
* with any ports requested by ListenPort.
*/
struct queued_listenaddr {
char *addr;
int port; /* <=0 if unspecified */
char *rdomain;
};
/* Resolved listen addresses, grouped by optional routing domain */
struct listenaddr {
char *rdomain;
struct addrinfo *addrs;
};
typedef struct {
u_int num_ports;
u_int ports_from_cmdline;
int ports[MAX_PORTS]; /* Port number to listen on. */
struct queued_listenaddr *queued_listen_addrs;
u_int num_queued_listens;
char **queued_listen_addrs;
int *queued_listen_ports;
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
int address_family; /* Address family used by the server. */
char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */
int num_host_key_files; /* Number of files for host keys. */
char *host_cert_files[MAX_HOSTCERTS]; /* Files containing host certs. */
int num_host_cert_files; /* Number of files for host certs. */
char *host_key_agent; /* ssh-agent socket for host keys. */
char *pid_file; /* Where to put our pid */
struct listenaddr *listen_addrs;
u_int num_listen_addrs;
int address_family; /* Address family used by the server. */
char *routing_domain; /* Bind session to routing domain */
char **host_key_files; /* Files containing host keys. */
u_int num_host_key_files; /* Number of files for host keys. */
char **host_cert_files; /* Files containing host certs. */
u_int num_host_cert_files; /* Number of files for host certs. */
char *host_key_agent; /* ssh-agent socket for host keys. */
char *pid_file; /* Where to put our pid */
int login_grace_time; /* Disconnect if no auth in this time
* (sec). */
int permit_root_login; /* PERMIT_*, see above */
@ -134,13 +145,13 @@ typedef struct {
int allow_agent_forwarding;
int disable_forwarding;
u_int num_allow_users;
char *allow_users[MAX_ALLOW_USERS];
char **allow_users;
u_int num_deny_users;
char *deny_users[MAX_DENY_USERS];
char **deny_users;
u_int num_allow_groups;
char *allow_groups[MAX_ALLOW_GROUPS];
char **allow_groups;
u_int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS];
char **deny_groups;
u_int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
@ -148,7 +159,7 @@ typedef struct {
char *subsystem_args[MAX_SUBSYSTEMS];
u_int num_accept_env;
char *accept_env[MAX_ACCEPT_ENV];
char **accept_env;
int max_startups_begin;
int max_startups_rate;
@ -167,8 +178,8 @@ typedef struct {
* disconnect the session
*/
u_int num_authkeys_files; /* Files containing public keys */
char *authorized_keys_files[MAX_AUTHKEYS_FILES];
u_int num_authkeys_files; /* Files containing public keys */
char **authorized_keys_files;
char *adm_forced_command;
@ -194,7 +205,7 @@ typedef struct {
char *version_addendum; /* Appended to SSH banner */
u_int num_auth_methods;
char *auth_methods[MAX_AUTH_METHODS];
char **auth_methods;
int fingerprint_hash;
int expose_userauth_info;
@ -207,6 +218,7 @@ struct connection_info {
const char *address; /* remote address */
const char *laddress; /* local address */
int lport; /* local port */
const char *rdomain; /* routing domain if available */
};
@ -230,6 +242,7 @@ struct connection_info {
M_CP_STROPT(authorized_principals_command_user); \
M_CP_STROPT(hostbased_key_types); \
M_CP_STROPT(pubkey_key_types); \
M_CP_STROPT(routing_domain); \
M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
M_CP_STRARRAYOPT(allow_users, num_allow_users); \
M_CP_STRARRAYOPT(deny_users, num_deny_users); \
@ -237,7 +250,7 @@ struct connection_info {
M_CP_STRARRAYOPT(deny_groups, num_deny_groups); \
M_CP_STRARRAYOPT(accept_env, num_accept_env); \
M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \
M_CP_STRARRAYOPT_ALLOC(permitted_opens, num_permitted_opens); \
M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \
} while (0)
struct connection_info *get_connection_info(int, int);
@ -255,5 +268,9 @@ int server_match_spec_complete(struct connection_info *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *);
char *derelativise_path(const char *);
void servconf_add_hostkey(const char *, const int,
ServerOptions *, const char *path);
void servconf_add_hostcert(const char *, const int,
ServerOptions *, const char *path);
#endif /* SERVCONF_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: serverloop.c,v 1.198 2017/09/12 06:35:32 djm Exp $ */
/* $OpenBSD: serverloop.c,v 1.199 2017/10/23 05:08:00 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -99,6 +99,9 @@ static volatile sig_atomic_t received_sigterm = 0;
/* prototypes */
static void server_init_dispatch(void);
/* requested tunnel forwarding interface(s), shared with session.c */
char *tun_fwd_ifnames = NULL;
/*
* we write to this pipe if a SIGCHLD is caught in order to avoid
* the race between select() and child_terminated
@ -519,6 +522,7 @@ server_request_tun(struct ssh *ssh)
Channel *c = NULL;
int mode, tun;
int sock;
char *tmp, *ifname = NULL;
mode = packet_get_int();
switch (mode) {
@ -541,9 +545,10 @@ server_request_tun(struct ssh *ssh)
goto done;
tun = forced_tun_device;
}
sock = tun_open(tun, mode);
sock = tun_open(tun, mode, &ifname);
if (sock < 0)
goto done;
debug("Tunnel forwarding using interface %s", ifname);
c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
c->datagram = 1;
@ -553,6 +558,19 @@ server_request_tun(struct ssh *ssh)
sys_tun_outfilter, NULL, NULL);
#endif
/*
* Update the list of names exposed to the session
* XXX remove these if the tunnels are closed (won't matter
* much if they are already in the environment though)
*/
tmp = tun_fwd_ifnames;
xasprintf(&tun_fwd_ifnames, "%s%s%s",
tun_fwd_ifnames == NULL ? "" : tun_fwd_ifnames,
tun_fwd_ifnames == NULL ? "" : ",",
ifname);
free(tmp);
free(ifname);
done:
if (c == NULL)
packet_send_debug("Failed to open the tunnel device.");

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.292 2017/09/12 06:32:07 djm Exp $ */
/* $OpenBSD: session.c,v 1.293 2017/10/23 05:08:00 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -140,6 +140,7 @@ extern u_int utmp_len;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
extern Buffer loginmsg;
char *tun_fwd_ifnames; /* serverloop.c */
/* original command from peer. */
const char *original_command = NULL;
@ -1344,6 +1345,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
free(laddr);
child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
if (tun_fwd_ifnames != NULL)
child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
if (auth_info_file != NULL)
child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
if (s->ttyfd != -1)

91
sftp.1
View File

@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.110 2017/05/03 21:49:18 naddy Exp $
.\" $OpenBSD: sftp.1,v 1.113 2017/11/03 03:46:52 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: May 3 2017 $
.Dd $Mdocdate: November 3 2017 $
.Dt SFTP 1
.Os
.Sh NAME
@ -30,7 +30,6 @@
.Nd secure file transfer program
.Sh SYNOPSIS
.Nm sftp
.Bk -words
.Op Fl 46aCfpqrv
.Op Fl B Ar buffer_size
.Op Fl b Ar batchfile
@ -44,54 +43,55 @@
.Op Fl R Ar num_requests
.Op Fl S Ar program
.Op Fl s Ar subsystem | sftp_server
.Ar host
.Ek
.Nm sftp
.Oo Ar user Ns @ Oc Ns
.Ar host Ns Op : Ns Ar
.Nm sftp
.Oo
.Ar user Ns @ Oc Ns
.Ar host Ns Oo : Ns Ar dir Ns
.Op Ar /
.Oc
.Nm sftp
.Fl b Ar batchfile
.Oo Ar user Ns @ Oc Ns Ar host
.Ar destination
.Sh DESCRIPTION
.Nm
is an interactive file transfer program, similar to
is a file transfer program, similar to
.Xr ftp 1 ,
which performs all operations over an encrypted
.Xr ssh 1
transport.
It may also use many features of ssh, such as public key authentication and
compression.
.Nm
connects and logs into the specified
.Ar host ,
then enters an interactive command mode.
.Pp
The second usage format will retrieve files automatically if a non-interactive
The
.Ar destination
may be specified either as
.Sm off
.Oo user @ Oc host Op : path
.Sm on
or as a URI in the form
.Sm off
.No sftp:// Oo user @ Oc host Oo : port Oc Op / path .
.Sm on
.Pp
If the
.Ar destination
includes a
.Ar path
and it is not a directory,
.Nm
will retrieve files automatically if a non-interactive
authentication method is used; otherwise it will do so after
successful interactive authentication.
.Pp
The third usage format allows
If no
.Ar path
is specified, or if the
.Ar path
is a directory,
.Nm
to start in a remote directory.
will log in to the specified
.Ar host
and enter interactive command mode, changing to the remote directory
if one was specified.
An optional trailing slash can be used to force the
.Ar path
to be interpreted as a directory.
.Pp
The final usage format allows for automated sessions using the
.Fl b
option.
In such cases, it is necessary to configure non-interactive authentication
to obviate the need to enter a password at connection time (see
.Xr sshd 8
and
.Xr ssh-keygen 1
for details).
.Pp
Since some usage formats use colon characters to delimit host names from path
names, IPv6 addresses must be enclosed in square brackets to avoid ambiguity.
Since the destination formats use colon characters to delimit host
names from path names or port numbers, IPv6 addresses must be
enclosed in square brackets to avoid ambiguity.
.Pp
The options are as follows:
.Bl -tag -width Ds
@ -121,7 +121,12 @@ Batch mode reads a series of commands from an input
instead of
.Em stdin .
Since it lacks user interaction it should be used in conjunction with
non-interactive authentication.
non-interactive authentication to obviate the need to enter a password
at connection time (see
.Xr sshd 8
and
.Xr ssh-keygen 1
for details).
A
.Ar batchfile
of
@ -296,9 +301,12 @@ must be escaped with backslashes
.It Ic bye
Quit
.Nm sftp .
.It Ic cd Ar path
.It Ic cd Op Ar path
Change remote directory to
.Ar path .
If
.Ar path
is not specified, then change directory to the one the session started in.
.It Ic chgrp Ar grp Ar path
Change group of file
.Ar path
@ -402,9 +410,12 @@ Note that
does not follow symbolic links when performing recursive transfers.
.It Ic help
Display help text.
.It Ic lcd Ar path
.It Ic lcd Op Ar path
Change local directory to
.Ar path .
If
.Ar path
is not specified, then change directory to the local user's home directory.
.It Ic lls Op Ar ls-options Op Ar path
Display local directory listing of either
.Ar path

90
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */
/* $OpenBSD: sftp.c,v 1.182 2017/11/03 03:46:52 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -217,8 +217,6 @@ static const struct CMD cmds[] = {
{ NULL, -1, -1 }
};
int interactive_loop(struct sftp_conn *, char *file1, char *file2);
/* ARGSUSED */
static void
killchild(int signo)
@ -1336,7 +1334,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
char *cp2, **argv;
int base = 0;
long l;
int i, cmdnum, optidx, argc;
int path1_mandatory = 0, i, cmdnum, optidx, argc;
/* Skip leading whitespace */
cp = cp + strspn(cp, WHITESPACE);
@ -1426,13 +1424,17 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
case I_RM:
case I_MKDIR:
case I_RMDIR:
case I_LMKDIR:
path1_mandatory = 1;
/* FALLTHROUGH */
case I_CHDIR:
case I_LCHDIR:
case I_LMKDIR:
if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
return -1;
/* Get pathname (mandatory) */
if (argc - optidx < 1) {
if (!path1_mandatory)
break; /* return a NULL path1 */
error("You must specify a path after a %s command.",
cmd);
return -1;
@ -1517,7 +1519,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag,
static int
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int err_abort)
const char *startdir, int err_abort)
{
char *path1, *path2, *tmp;
int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
@ -1604,6 +1606,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
err = do_rmdir(conn, path1);
break;
case I_CHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL) {
err = 1;
@ -1652,6 +1656,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
err = do_df(conn, path1, hflag, iflag);
break;
case I_LCHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup("~");
tmp = tilde_expand_filename(path1, getuid());
free(path1);
path1 = tmp;
@ -2138,11 +2144,11 @@ complete(EditLine *el, int ch)
}
#endif /* USE_LIBEDIT */
int
static int
interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
{
char *remote_path;
char *dir = NULL;
char *dir = NULL, *startdir = NULL;
char cmd[2048];
int err, interactive;
EditLine *el = NULL;
@ -2186,6 +2192,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
remote_path = do_realpath(conn, ".");
if (remote_path == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);
if (file1 != NULL) {
dir = xstrdup(file1);
@ -2196,8 +2203,9 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
mprintf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
if (parse_dispatch_command(conn, cmd,
&remote_path, 1) != 0) {
&remote_path, startdir, 1) != 0) {
free(dir);
free(startdir);
free(remote_path);
free(conn);
return (-1);
@ -2209,8 +2217,9 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
file2 == NULL ? "" : " ",
file2 == NULL ? "" : file2);
err = parse_dispatch_command(conn, cmd,
&remote_path, 1);
&remote_path, startdir, 1);
free(dir);
free(startdir);
free(remote_path);
free(conn);
return (err);
@ -2269,11 +2278,12 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
signal(SIGINT, cmd_interrupt);
err = parse_dispatch_command(conn, cmd, &remote_path,
batchmode);
startdir, batchmode);
if (err != 0)
break;
}
free(remote_path);
free(startdir);
free(conn);
#ifdef USE_LIBEDIT
@ -2366,19 +2376,16 @@ usage(void)
"[-i identity_file] [-l limit]\n"
" [-o ssh_option] [-P port] [-R num_requests] "
"[-S program]\n"
" [-s subsystem | sftp_server] host\n"
" %s [user@]host[:file ...]\n"
" %s [user@]host[:dir[/]]\n"
" %s -b batchfile [user@]host\n",
__progname, __progname, __progname, __progname);
" [-s subsystem | sftp_server] destination\n",
__progname);
exit(1);
}
int
main(int argc, char **argv)
{
int in, out, ch, err;
char *host = NULL, *userhost, *cp, *file2 = NULL;
int in, out, ch, err, tmp, port = -1;
char *host = NULL, *user, *cp, *file2 = NULL;
int debug_level = 0, sshver = 2;
char *file1 = NULL, *sftp_server = NULL;
char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
@ -2433,7 +2440,9 @@ main(int argc, char **argv)
addargs(&args, "-%c", ch);
break;
case 'P':
addargs(&args, "-oPort %s", optarg);
port = a2port(optarg);
if (port <= 0)
fatal("Bad port \"%s\"\n", optarg);
break;
case 'v':
if (debug_level < 3) {
@ -2516,34 +2525,39 @@ main(int argc, char **argv)
if (sftp_direct == NULL) {
if (optind == argc || argc > (optind + 2))
usage();
argv += optind;
userhost = xstrdup(argv[optind]);
if(argc > optind + 1)
file2 = argv[optind+1];
if ((host = strrchr(userhost, '@')) == NULL)
host = userhost;
else {
*host++ = '\0';
if (!userhost[0]) {
fprintf(stderr, "Missing username\n");
usage();
switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) {
case -1:
usage();
break;
case 0:
if (tmp != -1)
port = tmp;
break;
default:
if (parse_user_host_path(*argv, &user, &host,
&file1) == -1) {
/* Treat as a plain hostname. */
host = xstrdup(*argv);
host = cleanhostname(host);
}
addargs(&args, "-l");
addargs(&args, "%s", userhost);
break;
}
if (argv + 1)
file2 = *(argv + 1);
if ((cp = colon(host)) != NULL) {
*cp++ = '\0';
file1 = cp;
}
host = cleanhostname(host);
if (!*host) {
fprintf(stderr, "Missing hostname\n");
usage();
}
if (port != -1)
addargs(&args, "-oPort %d", port);
if (user != NULL) {
addargs(&args, "-l");
addargs(&args, "%s", user);
}
addargs(&args, "-oProtocol %d", sshver);
/* no subsystem if the server-spec contains a '/' */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.224 2017/07/24 04:34:28 djm Exp $ */
/* $OpenBSD: ssh-agent.c,v 1.226 2017/11/15 02:10:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -287,8 +287,11 @@ process_sign_request2(SocketEntry *e)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshkey_froms(e->request, &key)) != 0 ||
(r = sshbuf_get_string_direct(e->request, &data, &dlen)) != 0 ||
(r = sshbuf_get_u32(e->request, &flags)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
(r = sshbuf_get_u32(e->request, &flags)) != 0) {
error("%s: couldn't parse request: %s", __func__, ssh_err(r));
goto send;
}
if (flags & SSH_AGENT_OLD_SIGNATURE)
compat = SSH_BUG_SIGBLOB;
if ((id = lookup_identity(key)) == NULL) {
@ -472,6 +475,11 @@ process_lock_agent(SocketEntry *e, int lock)
static u_int fail_count = 0;
size_t pwlen;
/*
* This is deliberately fatal: the user has requested that we lock,
* but we can't parse their request properly. The only safe thing to
* do is abort.
*/
if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if (pwlen == 0) {
@ -529,7 +537,7 @@ no_identities(SocketEntry *e)
static void
process_add_smartcard_key(SocketEntry *e)
{
char *provider = NULL, *pin, canonical_provider[PATH_MAX];
char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
int r, i, count = 0, success = 0, confirm = 0;
u_int seconds;
time_t death = 0;
@ -538,17 +546,23 @@ process_add_smartcard_key(SocketEntry *e)
Identity *id;
if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
error("%s: buffer error: %s", __func__, ssh_err(r));
goto send;
}
while (sshbuf_len(e->request)) {
if ((r = sshbuf_get_u8(e->request, &type)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
if ((r = sshbuf_get_u8(e->request, &type)) != 0) {
error("%s: buffer error: %s", __func__, ssh_err(r));
goto send;
}
switch (type) {
case SSH_AGENT_CONSTRAIN_LIFETIME:
if ((r = sshbuf_get_u32(e->request, &seconds)) != 0)
fatal("%s: buffer error: %s",
if ((r = sshbuf_get_u32(e->request, &seconds)) != 0) {
error("%s: buffer error: %s",
__func__, ssh_err(r));
goto send;
}
death = monotime() + seconds;
break;
case SSH_AGENT_CONSTRAIN_CONFIRM:
@ -606,8 +620,10 @@ process_remove_smartcard_key(SocketEntry *e)
Identity *id, *nxt;
if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
(r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0) {
error("%s: buffer error: %s", __func__, ssh_err(r));
goto send;
}
free(pin);
if (realpath(provider, canonical_provider) == NULL) {

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.144 2017/07/08 18:32:54 jmc Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.145 2017/11/03 05:14:04 djm Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: July 8 2017 $
.Dd $Mdocdate: November 3 2017 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
@ -584,13 +584,20 @@ Specify a validity interval when signing a certificate.
A validity interval may consist of a single time, indicating that the
certificate is valid beginning now and expiring at that time, or may consist
of two times separated by a colon to indicate an explicit time interval.
The start time may be specified as a date in YYYYMMDD format, a time
in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting
of a minus sign followed by a relative time in the format described in the
.Pp
The start time may be specified as the string
.Dq always
to indicate the certificate has no specified start time,
a date in YYYYMMDD format, a time in YYYYMMDDHHMMSS format,
a relative time (to the current time) consisting of a minus sign followed by
an interval in the format described in the
TIME FORMATS section of
.Xr sshd_config 5 .
The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or
a relative time starting with a plus character.
.Pp
The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time,
a relative time starting with a plus character or the string
.Dq forever
to indicate that the certificate has no expirty date.
.Pp
For example:
.Dq +52w1d
@ -601,6 +608,8 @@ For example:
(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011),
.Dq -1d:20110101
(valid from yesterday to midnight, January 1st, 2011).
.Dq -1m:forever
(valid from one minute ago and never expiring).
.It Fl v
Verbose mode.
Causes

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.307 2017/07/07 03:53:12 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.308 2017/11/03 05:14:04 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1861,7 +1861,7 @@ parse_absolute_time(const char *s)
s, s + 4, s + 6, s + 8, s + 10, s + 12);
break;
default:
fatal("Invalid certificate time format %s", s);
fatal("Invalid certificate time format \"%s\"", s);
}
memset(&tm, 0, sizeof(tm));
@ -1894,8 +1894,8 @@ parse_cert_times(char *timespec)
/*
* from:to, where
* from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
* to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
* from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "always"
* to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "forever"
*/
from = xstrdup(timespec);
to = strchr(from, ':');
@ -1905,11 +1905,15 @@ parse_cert_times(char *timespec)
if (*from == '-' || *from == '+')
cert_valid_from = parse_relative_time(from, now);
else if (strcmp(from, "always") == 0)
cert_valid_from = 0;
else
cert_valid_from = parse_absolute_time(from);
if (*to == '-' || *to == '+')
cert_valid_to = parse_relative_time(to, now);
else if (strcmp(to, "forever") == 0)
cert_valid_to = ~(u_int64_t)0;
else
cert_valid_to = parse_absolute_time(to);

50
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh.1,v 1.384 2017/09/21 19:16:53 markus Exp $
.Dd $Mdocdate: September 21 2017 $
.\" $OpenBSD: ssh.1,v 1.389 2017/11/03 02:29:17 djm Exp $
.Dd $Mdocdate: November 3 2017 $
.Dt SSH 1
.Os
.Sh NAME
@ -42,7 +42,6 @@
.Nd OpenSSH SSH client (remote login program)
.Sh SYNOPSIS
.Nm ssh
.Bk -words
.Op Fl 46AaCfGgKkMNnqsTtVvXxYy
.Op Fl b Ar bind_address
.Op Fl c Ar cipher_spec
@ -52,7 +51,7 @@
.Op Fl F Ar configfile
.Op Fl I Ar pkcs11
.Op Fl i Ar identity_file
.Op Fl J Oo Ar user Ns @ Oc Ns Ar host Ns Op : Ns Ar port
.Op Fl J Ar destination
.Op Fl L Ar address
.Op Fl l Ar login_name
.Op Fl m Ar mac_spec
@ -64,9 +63,8 @@
.Op Fl S Ar ctl_path
.Op Fl W Ar host : Ns Ar port
.Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun
.Oo Ar user Ns @ Oc Ns Ar hostname
.Ar destination
.Op Ar command
.Ek
.Sh DESCRIPTION
.Nm
(SSH client) is a program for logging into a remote machine and for
@ -79,15 +77,20 @@ sockets can also be forwarded over the secure channel.
.Pp
.Nm
connects and logs into the specified
.Ar hostname
(with optional
.Ar user
name).
.Ar destination ,
which may be specified as either
.Sm off
.Oo user @ Oc hostname
.Sm on
or a URI of the form
.Sm off
.No ssh:// Oo user @ Oc hostname Op : port .
.Sm on
The user must prove
his/her identity to the remote machine using one of several methods
(see below).
.Pp
If
If a
.Ar command
is specified,
it is executed on the remote host instead of a login shell.
@ -287,17 +290,11 @@ by appending
.Pa -cert.pub
to identity filenames.
.Pp
.It Fl J Xo
.Sm off
.Op Ar user No @
.Ar host
.Op : Ar port
.Sm on
.Xc
.It Fl J Ar destination
Connect to the target host by first making a
.Nm
connection to the jump
.Ar host
connection to the jump host described by
.Ar destination
and then establishing a TCP forwarding to the ultimate destination from
there.
Multiple jump hops may be specified separated by comma characters.
@ -1393,6 +1390,17 @@ This is set to the name of the tty (path to the device) associated
with the current shell or command.
If the current session has no tty,
this variable is not set.
.It Ev SSH_TUNNEL
Optionally set by
.Xr sshd 8
to contain the interface names assigned if tunnel forwarding was
requested by the client.
.It Ev SSH_USER_AUTH
Optionally set by
.Xr sshd 8 ,
this variable may contain a pathname to a file that lists the authentication
methods successfully used when the session was established, including any
public keys that were used.
.It Ev TZ
This variable is set to indicate the present time zone if it
was set when the daemon was started (i.e. the daemon passes the value
@ -1474,7 +1482,7 @@ accessible by others (read/write/execute).
will simply ignore a private key file if it is accessible by others.
It is possible to specify a passphrase when
generating the key which will be used to encrypt the
sensitive part of this file using 3DES.
sensitive part of this file using AES-128.
.Pp
.It Pa ~/.ssh/id_dsa.pub
.It Pa ~/.ssh/id_ecdsa.pub

190
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.464 2017/09/21 19:16:53 markus Exp $ */
/* $OpenBSD: ssh.c,v 1.469 2017/11/01 00:04:15 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -168,6 +168,10 @@ char *config = NULL;
*/
char *host;
/* Various strings used to to percent_expand() arguments */
static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
static char uidstr[32], *host_arg, *conn_hash_hex;
/* socket address the host resolves to */
struct sockaddr_storage hostaddr;
@ -203,13 +207,13 @@ usage(void)
" [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n"
" [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n"
" [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n"
" [user@]hostname [command]\n"
" destination [command]\n"
);
exit(255);
}
static int ssh_session2(struct ssh *);
static void load_public_identity_files(void);
static int ssh_session2(struct ssh *, struct passwd *);
static void load_public_identity_files(struct passwd *);
static void main_sigchld_handler(int);
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
@ -456,14 +460,14 @@ resolve_canonicalize(char **hostp, int port)
* file if the user specifies a config file on the command line.
*/
static void
process_config_files(const char *host_arg, struct passwd *pw, int post_canon)
process_config_files(const char *host_name, struct passwd *pw, int post_canon)
{
char buf[PATH_MAX];
int r;
if (config != NULL) {
if (strcasecmp(config, "none") != 0 &&
!read_config_file(config, pw, host, host_arg, &options,
!read_config_file(config, pw, host, host_name, &options,
SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)))
fatal("Can't open user config file %.100s: "
"%.100s", config, strerror(errno));
@ -471,13 +475,13 @@ process_config_files(const char *host_arg, struct passwd *pw, int post_canon)
r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
_PATH_SSH_USER_CONFFILE);
if (r > 0 && (size_t)r < sizeof(buf))
(void)read_config_file(buf, pw, host, host_arg,
(void)read_config_file(buf, pw, host, host_name,
&options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
(post_canon ? SSHCONF_POSTCANON : 0));
/* Read systemwide configuration file after user config. */
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
host, host_arg, &options,
host, host_name, &options,
post_canon ? SSHCONF_POSTCANON : 0);
}
}
@ -511,9 +515,8 @@ main(int ac, char **av)
struct ssh *ssh = NULL;
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
int config_test = 0, opt_terminated = 0;
char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile;
char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile;
char cname[NI_MAXHOST];
struct stat st;
struct passwd *pw;
extern int optind, optreset;
@ -846,14 +849,18 @@ main(int ac, char **av)
options.control_master = SSHCTL_MASTER_YES;
break;
case 'p':
options.port = a2port(optarg);
if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
exit(255);
if (options.port == -1) {
options.port = a2port(optarg);
if (options.port <= 0) {
fprintf(stderr, "Bad port '%s'\n",
optarg);
exit(255);
}
}
break;
case 'l':
options.user = optarg;
if (options.user == NULL)
options.user = optarg;
break;
case 'L':
@ -933,16 +940,38 @@ main(int ac, char **av)
av += optind;
if (ac > 0 && !host) {
if (strrchr(*av, '@')) {
int tport;
char *tuser;
switch (parse_ssh_uri(*av, &tuser, &host, &tport)) {
case -1:
usage();
break;
case 0:
if (options.user == NULL) {
options.user = tuser;
tuser = NULL;
}
free(tuser);
if (options.port == -1 && tport != -1)
options.port = tport;
break;
default:
p = xstrdup(*av);
cp = strrchr(p, '@');
if (cp == NULL || cp == p)
usage();
options.user = p;
*cp = '\0';
host = xstrdup(++cp);
} else
host = xstrdup(*av);
if (cp != NULL) {
if (cp == p)
usage();
if (options.user == NULL) {
options.user = p;
p = NULL;
}
*cp++ = '\0';
host = xstrdup(cp);
free(p);
} else
host = p;
break;
}
if (ac > 1 && !opt_terminated) {
optind = optreset = 1;
goto again;
@ -994,9 +1023,9 @@ main(int ac, char **av)
if (logfile != NULL)
log_redirect_stderr_to(logfile);
log_init(argv0,
options.log_level == SYSLOG_LEVEL_NOT_SET ?
options.log_level == SYSLOG_LEVEL_NOT_SET ?
SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
SYSLOG_FACILITY_USER : options.log_facility,
!use_syslog);
@ -1035,7 +1064,7 @@ main(int ac, char **av)
* If CanonicalizePermittedCNAMEs have been specified but
* other canonicalization did not happen (by not being requested
* or by failing with fallback) then the hostname may still be changed
* as a result of CNAME following.
* as a result of CNAME following.
*
* Try to resolve the bare hostname name using the system resolver's
* usual search rules and then apply the CNAME follow rules.
@ -1177,6 +1206,7 @@ main(int ac, char **av)
if (options.user == NULL)
options.user = xstrdup(pw->pw_name);
/* Set up strings used to percent_expand() arguments */
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("gethostname: %s", strerror(errno));
strlcpy(shorthost, thishost, sizeof(shorthost));
@ -1194,24 +1224,11 @@ main(int ac, char **av)
ssh_digest_free(md);
conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1));
if (options.local_command != NULL) {
debug3("expanding LocalCommand: %s", options.local_command);
cp = options.local_command;
options.local_command = percent_expand(cp,
"C", conn_hash_hex,
"L", shorthost,
"d", pw->pw_dir,
"h", host,
"l", thishost,
"n", host_arg,
"p", portstr,
"r", options.user,
"u", pw->pw_name,
(char *)NULL);
debug3("expanded LocalCommand: %s", options.local_command);
free(cp);
}
/*
* Expand tokens in arguments. NB. LocalCommand is expanded later,
* after port-forwarding is set up, so it may pick up any local
* tunnel interface name allocated.
*/
if (options.remote_command != NULL) {
debug3("expanding RemoteCommand: %s", options.remote_command);
cp = options.remote_command;
@ -1230,7 +1247,6 @@ main(int ac, char **av)
free(cp);
buffer_append(&command, options.remote_command,
strlen(options.remote_command));
}
if (options.control_path != NULL) {
@ -1401,7 +1417,7 @@ main(int ac, char **av)
}
}
/* load options.identity_files */
load_public_identity_files();
load_public_identity_files(pw);
/* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */
if (options.identity_agent &&
@ -1465,7 +1481,7 @@ main(int ac, char **av)
}
skip_connect:
exit_status = ssh_session2(ssh);
exit_status = ssh_session2(ssh, pw);
packet_close();
if (options.control_path != NULL && muxserver_sock != -1)
@ -1571,7 +1587,7 @@ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
channel_update_permitted_opens(ssh, rfwd->handle, -1);
}
}
if (type == SSH2_MSG_REQUEST_FAILURE) {
if (options.exit_on_forward_failure) {
if (rfwd->listen_path != NULL)
@ -1633,7 +1649,7 @@ ssh_init_stdio_forwarding(struct ssh *ssh)
}
static void
ssh_init_forwarding(struct ssh *ssh)
ssh_init_forwarding(struct ssh *ssh, char **ifname)
{
int success = 0;
int i;
@ -1691,14 +1707,15 @@ ssh_init_forwarding(struct ssh *ssh)
/* Initiate tunnel forwarding. */
if (options.tun_open != SSH_TUNMODE_NO) {
if (client_request_tun_fwd(ssh, options.tun_open,
options.tun_local, options.tun_remote) == -1) {
if ((*ifname = client_request_tun_fwd(ssh,
options.tun_open, options.tun_local,
options.tun_remote)) == NULL) {
if (options.exit_on_forward_failure)
fatal("Could not request tunnel forwarding.");
else
error("Could not request tunnel forwarding.");
}
}
}
}
static void
@ -1807,14 +1824,35 @@ ssh_session2_open(struct ssh *ssh)
}
static int
ssh_session2(struct ssh *ssh)
ssh_session2(struct ssh *ssh, struct passwd *pw)
{
int id = -1;
int devnull, id = -1;
char *cp, *tun_fwd_ifname = NULL;
/* XXX should be pre-session */
if (!options.control_persist)
ssh_init_stdio_forwarding(ssh);
ssh_init_forwarding(ssh);
ssh_init_forwarding(ssh, &tun_fwd_ifname);
if (options.local_command != NULL) {
debug3("expanding LocalCommand: %s", options.local_command);
cp = options.local_command;
options.local_command = percent_expand(cp,
"C", conn_hash_hex,
"L", shorthost,
"d", pw->pw_dir,
"h", host,
"l", thishost,
"n", host_arg,
"p", portstr,
"r", options.user,
"u", pw->pw_name,
"T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname,
(char *)NULL);
debug3("expanded LocalCommand: %s", options.local_command);
free(cp);
}
/* Start listening for multiplex clients */
if (!packet_get_mux())
@ -1871,6 +1909,22 @@ ssh_session2(struct ssh *ssh)
options.permit_local_command)
ssh_local_cmd(options.local_command);
/*
* stdout is now owned by the session channel; clobber it here
* so future channel closes are propagated to the local fd.
* NB. this can only happen after LocalCommand has completed,
* as it may want to write to stdout.
*/
if (!need_controlpersist_detach) {
if ((devnull = open(_PATH_DEVNULL, O_WRONLY)) == -1)
error("%s: open %s: %s", __func__,
_PATH_DEVNULL, strerror(errno));
if (dup2(devnull, STDOUT_FILENO) < 0)
fatal("%s: dup2() stdout failed", __func__);
if (devnull > STDERR_FILENO)
close(devnull);
}
/*
* If requested and we are not interested in replies to remote
* forwarding requests, then let ssh continue in the background.
@ -1890,12 +1944,10 @@ ssh_session2(struct ssh *ssh)
/* Loads all IdentityFile and CertificateFile keys */
static void
load_public_identity_files(void)
load_public_identity_files(struct passwd *pw)
{
char *filename, *cp, thishost[NI_MAXHOST];
char *pwdir = NULL, *pwname = NULL;
char *filename, *cp;
struct sshkey *public;
struct passwd *pw;
int i;
u_int n_ids, n_certs;
char *identity_files[SSH_MAX_IDENTITY_FILES];
@ -1934,11 +1986,6 @@ load_public_identity_files(void)
#endif /* ENABLE_PKCS11 */
if ((pw = getpwuid(original_real_uid)) == NULL)
fatal("load_public_identity_files: getpwuid failed");
pwname = xstrdup(pw->pw_name);
pwdir = xstrdup(pw->pw_dir);
if (gethostname(thishost, sizeof(thishost)) == -1)
fatal("load_public_identity_files: gethostname: %s",
strerror(errno));
for (i = 0; i < options.num_identity_files; i++) {
if (n_ids >= SSH_MAX_IDENTITY_FILES ||
strcasecmp(options.identity_files[i], "none") == 0) {
@ -1948,8 +1995,8 @@ load_public_identity_files(void)
}
cp = tilde_expand_filename(options.identity_files[i],
original_real_uid);
filename = percent_expand(cp, "d", pwdir,
"u", pwname, "l", thishost, "h", host,
filename = percent_expand(cp, "d", pw->pw_dir,
"u", pw->pw_name, "l", thishost, "h", host,
"r", options.user, (char *)NULL);
free(cp);
public = key_load_public(filename, NULL);
@ -1994,8 +2041,8 @@ load_public_identity_files(void)
for (i = 0; i < options.num_certificate_files; i++) {
cp = tilde_expand_filename(options.certificate_files[i],
original_real_uid);
filename = percent_expand(cp, "d", pwdir,
"u", pwname, "l", thishost, "h", host,
filename = percent_expand(cp, "d", pw->pw_dir,
"u", pw->pw_name, "l", thishost, "h", host,
"r", options.user, (char *)NULL);
free(cp);
@ -2028,11 +2075,6 @@ load_public_identity_files(void)
memcpy(options.certificate_files,
certificate_files, sizeof(certificate_files));
memcpy(options.certificates, certificates, sizeof(certificates));
explicit_bzero(pwname, strlen(pwname));
free(pwname);
explicit_bzero(pwdir, strlen(pwdir));
free(pwdir);
}
static void

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.256 2017/09/21 19:16:53 markus Exp $
.Dd $Mdocdate: September 21 2017 $
.\" $OpenBSD: ssh_config.5,v 1.262 2017/10/24 06:27:42 jmc Exp $
.Dd $Mdocdate: October 24 2017 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@ -1198,13 +1198,14 @@ For example, the following directive would connect via an HTTP proxy at
ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
.Ed
.It Cm ProxyJump
Specifies one or more jump proxies as
Specifies one or more jump proxies as either
.Xo
.Sm off
.Op Ar user No @
.Ar host
.Op : Ns Ar port
.Sm on
or an ssh URI
.Xc .
Multiple proxies may be separated by comma characters and will be visited
sequentially.
@ -1674,6 +1675,18 @@ pool,
the following entry (in authorized_keys) could be used:
.Pp
.Dl from=\&"!*.dialup.example.com,*.example.com\&"
.Pp
Note that a negated match will never produce a positive result by itself.
For example, attempting to match
.Qq host3
against the following pattern-list will fail:
.Pp
.Dl from=\&"!host1,!host2\&"
.Pp
The solution here is to include a term that will yield a positive match,
such as a wildcard:
.Pp
.Dl from=\&"!host1,!host2,*\&"
.Sh TOKENS
Arguments to some keywords can make use of tokens,
which are expanded at runtime:
@ -1683,7 +1696,7 @@ which are expanded at runtime:
A literal
.Sq % .
.It \&%C
Shorthand for %l%h%p%r.
Hash of %l%h%p%r.
.It %d
Local user's home directory.
.It %h
@ -1700,6 +1713,15 @@ The original remote hostname, as given on the command line.
The remote port.
.It %r
The remote username.
.It \&%T
The local
.Xr tun 4
or
.Xr tap 4
network interface assigned if
tunnel forwarding was requested, or
.Qq NONE
otherwise.
.It %u
The local username.
.El
@ -1722,7 +1744,7 @@ and
accept the tokens %%, %d, %h, %l, %r, and %u.
.Pp
.Cm LocalCommand
accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, and %u.
accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, %T, and %u.
.Pp
.Cm ProxyCommand
accepts the tokens %%, %h, %p, and %r.

22
sshd.8
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd.8,v 1.291 2017/06/24 06:28:50 jmc Exp $
.Dd $Mdocdate: June 24 2017 $
.\" $OpenBSD: sshd.8,v 1.293 2017/11/03 03:18:53 dtucker Exp $
.Dd $Mdocdate: November 3 2017 $
.Dt SSHD 8
.Os
.Sh NAME
@ -100,20 +100,22 @@ Specify the connection parameters to use for the
extended test mode.
If provided, any
.Cm Match
directives in the configuration file
that would apply to the specified user, host, and address will be set before
the configuration is written to standard output.
The connection parameters are supplied as keyword=value pairs.
directives in the configuration file that would apply are applied before the
configuration is written to standard output.
The connection parameters are supplied as keyword=value pairs and may be
supplied in any order, either with multiple
.Fl C
options or as a comma-separated list.
The keywords are
.Dq addr,
.Dq user ,
.Dq host ,
.Dq laddr ,
.Dq lport ,
and
.Dq addr .
All are required and may be supplied in any order, either with multiple
.Fl C
options or as a comma-separated list.
.Dq rdomain
and correspond to source address, user, resolved source host name,
local address, local port number and routing domain respectively.
.It Fl c Ar host_certificate_file
Specifies a path to a certificate file to identify
.Nm

182
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.492 2017/09/12 06:32:07 djm Exp $ */
/* $OpenBSD: sshd.c,v 1.499 2017/11/14 00:45:29 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -144,7 +144,12 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE;
*/
int debug_flag = 0;
/* Flag indicating that the daemon should only test the configuration and keys. */
/*
* Indicating that the daemon should only test the configuration and keys.
* If test_flag > 1 ("-T" flag), then sshd will also dump the effective
* configuration, optionally using connection information provided by the
* "-C" flag.
*/
int test_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
@ -485,7 +490,7 @@ sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out)
void
destroy_sensitive_data(void)
{
int i;
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
@ -504,7 +509,7 @@ void
demote_sensitive_data(void)
{
struct sshkey *tmp;
int i;
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (sensitive_data.host_keys[i]) {
@ -728,7 +733,7 @@ list_hostkey_types(void)
Buffer b;
const char *p;
char *ret;
int i;
u_int i;
struct sshkey *key;
buffer_init(&b);
@ -788,7 +793,7 @@ list_hostkey_types(void)
static struct sshkey *
get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
{
int i;
u_int i;
struct sshkey *key;
for (i = 0; i < options.num_host_key_files; i++) {
@ -828,7 +833,7 @@ get_hostkey_private_by_type(int type, int nid, struct ssh *ssh)
struct sshkey *
get_hostkey_by_index(int ind)
{
if (ind < 0 || ind >= options.num_host_key_files)
if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_keys[ind]);
}
@ -836,7 +841,7 @@ get_hostkey_by_index(int ind)
struct sshkey *
get_hostkey_public_by_index(int ind, struct ssh *ssh)
{
if (ind < 0 || ind >= options.num_host_key_files)
if (ind < 0 || (u_int)ind >= options.num_host_key_files)
return (NULL);
return (sensitive_data.host_pubkeys[ind]);
}
@ -844,7 +849,7 @@ get_hostkey_public_by_index(int ind, struct ssh *ssh)
int
get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh)
{
int i;
u_int i;
for (i = 0; i < options.num_host_key_files; i++) {
if (key_is_cert(key)) {
@ -873,7 +878,8 @@ notify_hostkeys(struct ssh *ssh)
{
struct sshbuf *buf;
struct sshkey *key;
int i, nkeys, r;
u_int i, nkeys;
int r;
char *fp;
/* Some clients cannot cope with the hostkeys message, skip those. */
@ -904,7 +910,7 @@ notify_hostkeys(struct ssh *ssh)
packet_put_string(sshbuf_ptr(buf), sshbuf_len(buf));
nkeys++;
}
debug3("%s: sent %d hostkeys", __func__, nkeys);
debug3("%s: sent %u hostkeys", __func__, nkeys);
if (nkeys == 0)
fatal("%s: no hostkeys", __func__);
packet_send();
@ -1057,13 +1063,13 @@ server_accept_inetd(int *sock_in, int *sock_out)
* Listen for TCP connections
*/
static void
server_listen(void)
listen_on_addrs(struct listenaddr *la)
{
int ret, listen_sock, on = 1;
int ret, listen_sock;
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
for (ai = la->addrs; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
if (num_listen_socks >= MAX_LISTEN_SOCKS)
@ -1093,13 +1099,13 @@ server_listen(void)
close(listen_sock);
continue;
}
/*
* Set socket options.
* Allow local port reuse in TIME_WAIT.
*/
if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on)) == -1)
error("setsockopt SO_REUSEADDR: %s", strerror(errno));
/* Socket options */
set_reuseaddr(listen_sock);
if (la->rdomain != NULL &&
set_rdomain(listen_sock, la->rdomain) == -1) {
close(listen_sock);
continue;
}
/* Only communicate in IPv6 over AF_INET6 sockets. */
if (ai->ai_family == AF_INET6)
@ -1121,9 +1127,28 @@ server_listen(void)
if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
fatal("listen on [%s]:%s: %.100s",
ntop, strport, strerror(errno));
logit("Server listening on %s port %s.", ntop, strport);
logit("Server listening on %s port %s%s%s.",
ntop, strport,
la->rdomain == NULL ? "" : " rdomain ",
la->rdomain == NULL ? "" : la->rdomain);
}
freeaddrinfo(options.listen_addrs);
}
static void
server_listen(void)
{
u_int i;
for (i = 0; i < options.num_listen_addrs; i++) {
listen_on_addrs(&options.listen_addrs[i]);
freeaddrinfo(options.listen_addrs[i].addrs);
free(options.listen_addrs[i].rdomain);
memset(&options.listen_addrs[i], 0,
sizeof(options.listen_addrs[i]));
}
free(options.listen_addrs);
options.listen_addrs = NULL;
options.num_listen_addrs = 0;
if (!num_listen_socks)
fatal("Cannot bind any address.");
@ -1432,6 +1457,46 @@ check_ip_options(struct ssh *ssh)
#endif /* IP_OPTIONS */
}
/* Set the routing domain for this process */
static void
set_process_rdomain(struct ssh *ssh, const char *name)
{
#if defined(HAVE_SYS_SET_PROCESS_RDOMAIN)
if (name == NULL)
return; /* default */
if (strcmp(name, "%D") == 0) {
/* "expands" to routing domain of connection */
if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
return;
}
/* NB. We don't pass 'ssh' to sys_set_process_rdomain() */
return sys_set_process_rdomain(name);
#elif defined(__OpenBSD__)
int rtable, ortable = getrtable();
const char *errstr;
if (name == NULL)
return; /* default */
if (strcmp(name, "%D") == 0) {
/* "expands" to routing domain of connection */
if ((name = ssh_packet_rdomain_in(ssh)) == NULL)
return;
}
rtable = (int)strtonum(name, 0, 255, &errstr);
if (errstr != NULL) /* Shouldn't happen */
fatal("Invalid routing domain \"%s\": %s", name, errstr);
if (rtable != ortable && setrtable(rtable) != 0)
fatal("Unable to set routing domain %d: %s",
rtable, strerror(errno));
debug("%s: set routing domain %d (was %d)", __func__, rtable, ortable);
#else /* defined(__OpenBSD__) */
fatal("Unable to set routing domain: not supported in this platform");
#endif
}
/*
* Main program for the daemon.
*/
@ -1441,20 +1506,19 @@ main(int ac, char **av)
struct ssh *ssh = NULL;
extern char *optarg;
extern int optind;
int r, opt, i, j, on = 1, already_daemon;
int r, opt, on = 1, already_daemon, remote_port;
int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip;
int remote_port;
const char *remote_ip, *rdomain;
char *fp, *line, *laddr, *logfile = NULL;
int config_s[2] = { -1 , -1 };
u_int n;
u_int i, j;
u_int64_t ibytes, obytes;
mode_t new_umask;
struct sshkey *key;
struct sshkey *pubkey;
int keytype;
Authctxt *authctxt;
struct connection_info *connection_info = get_connection_info(0, 0);
struct connection_info *connection_info = NULL;
ssh_malloc_init(); /* must be called before any mallocs */
@ -1467,7 +1531,7 @@ main(int ac, char **av)
saved_argc = ac;
rexec_argc = ac;
saved_argv = xcalloc(ac + 1, sizeof(*saved_argv));
for (i = 0; i < ac; i++)
for (i = 0; (int)i < ac; i++)
saved_argv[i] = xstrdup(av[i]);
saved_argv[i] = NULL;
@ -1500,12 +1564,8 @@ main(int ac, char **av)
config_file_name = optarg;
break;
case 'c':
if (options.num_host_cert_files >= MAX_HOSTCERTS) {
fprintf(stderr, "too many host certificates.\n");
exit(1);
}
options.host_cert_files[options.num_host_cert_files++] =
derelativise_path(optarg);
servconf_add_hostcert("[command-line]", 0,
&options, optarg);
break;
case 'd':
if (debug_flag == 0) {
@ -1564,12 +1624,8 @@ main(int ac, char **av)
/* protocol 1, ignored */
break;
case 'h':
if (options.num_host_key_files >= MAX_HOSTKEYS) {
fprintf(stderr, "too many host keys.\n");
exit(1);
}
options.host_key_files[options.num_host_key_files++] =
derelativise_path(optarg);
servconf_add_hostkey("[command-line]", 0,
&options, optarg);
break;
case 't':
test_flag = 1;
@ -1578,6 +1634,7 @@ main(int ac, char **av)
test_flag = 2;
break;
case 'C':
connection_info = get_connection_info(0, 0);
if (parse_server_match_testspec(connection_info,
optarg) == -1)
exit(1);
@ -1646,14 +1703,10 @@ main(int ac, char **av)
sensitive_data.have_ssh2_key = 0;
/*
* If we're doing an extended config test, make sure we have all of
* the parameters we need. If we're not doing an extended test,
* do not silently ignore connection test params.
* If we're not doing an extended test do not silently ignore connection
* test params.
*/
if (test_flag >= 2 && server_match_spec_complete(connection_info) == 0)
fatal("user, host and addr are all required when testing "
"Match configs");
if (test_flag < 2 && server_match_spec_complete(connection_info) >= 0)
if (test_flag < 2 && connection_info != NULL)
fatal("Config test connection parameter (-C) provided without "
"test mode (-T)");
@ -1704,12 +1757,12 @@ main(int ac, char **av)
* and warns for trivial misconfigurations that could break login.
*/
if (options.num_auth_methods != 0) {
for (n = 0; n < options.num_auth_methods; n++) {
if (auth2_methods_valid(options.auth_methods[n],
for (i = 0; i < options.num_auth_methods; i++) {
if (auth2_methods_valid(options.auth_methods[i],
1) == 0)
break;
}
if (n >= options.num_auth_methods)
if (i >= options.num_auth_methods)
fatal("AuthenticationMethods cannot be satisfied by "
"enabled authentication methods");
}
@ -1847,7 +1900,7 @@ main(int ac, char **av)
continue;
}
sensitive_data.host_certificates[j] = key;
debug("host certificate: #%d type %d %s", j, key->type,
debug("host certificate: #%u type %d %s", j, key->type,
key_type(key));
}
@ -1871,8 +1924,13 @@ main(int ac, char **av)
}
if (test_flag > 1) {
if (server_match_spec_complete(connection_info) == 1)
parse_server_match_config(&options, connection_info);
/*
* If no connection info was provided by -C then use
* use a blank one that will cause no predicate to match.
*/
if (connection_info == NULL)
connection_info = get_connection_info(0, 0);
parse_server_match_config(&options, connection_info);
dump_config(&options);
}
@ -1891,8 +1949,10 @@ main(int ac, char **av)
debug("setgroups() failed: %.200s", strerror(errno));
if (rexec_flag) {
if (rexec_argc < 0)
fatal("rexec_argc %d < 0", rexec_argc);
rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *));
for (i = 0; i < rexec_argc; i++) {
for (i = 0; i < (u_int)rexec_argc; i++) {
debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
rexec_argv[i] = saved_argv[i];
}
@ -2090,6 +2150,9 @@ main(int ac, char **av)
cleanup_exit(255);
}
if (options.routing_domain != NULL)
set_process_rdomain(ssh, options.routing_domain);
/*
* The rest of the code depends on the fact that
* ssh_remote_ipaddr() caches the remote ip, even if
@ -2101,10 +2164,15 @@ main(int ac, char **av)
audit_connection_from(remote_ip, remote_port);
#endif
rdomain = ssh_packet_rdomain_in(ssh);
/* Log the connection. */
laddr = get_local_ipaddr(sock_in);
verbose("Connection from %s port %d on %s port %d",
remote_ip, remote_port, laddr, ssh_local_port(ssh));
verbose("Connection from %s port %d on %s port %d%s%s%s",
remote_ip, remote_port, laddr, ssh_local_port(ssh),
rdomain == NULL ? "" : " rdomain \"",
rdomain == NULL ? "" : rdomain,
rdomain == NULL ? "" : "\"");
free(laddr);
/*

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd_config.5,v 1.253 2017/09/27 06:45:53 jmc Exp $
.Dd $Mdocdate: September 27 2017 $
.\" $OpenBSD: sshd_config.5,v 1.260 2017/10/26 06:44:01 jmc Exp $
.Dd $Mdocdate: October 26 2017 $
.Dt SSHD_CONFIG 5
.Os
.Sh NAME
@ -48,6 +48,7 @@ reads configuration data from
.Fl f
on the command line).
The file contains keyword-argument pairs, one per line.
For each keyword, the first obtained value will be used.
Lines starting with
.Ql #
and empty lines are interpreted as comments.
@ -908,31 +909,47 @@ The following forms may be used:
.It
.Cm ListenAddress
.Sm off
.Ar host | Ar IPv4_addr | Ar IPv6_addr
.Ar hostname | address
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Ar host | Ar IPv4_addr : Ar port
.Ar hostname : port
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Oo
.Ar host | Ar IPv6_addr Oc : Ar port
.Ar IPv4_address : port
.Sm on
.Op Cm rdomain Ar domain
.It
.Cm ListenAddress
.Sm off
.Oo Ar hostname | address Oc : Ar port
.Sm on
.Op Cm rdomain Ar domain
.El
.Pp
The optional
.Cm rdomain
qualifier requests
.Xr sshd 8
listen in an explicit routing domain.
If
.Ar port
is not specified,
sshd will listen on the address and all
.Cm Port
options specified.
The default is to listen on all local addresses.
The default is to listen on all local addresses on the current default
routing domain.
Multiple
.Cm ListenAddress
options are permitted.
For more information on routing domains, see
.Xr rdomain 4 .
.It Cm LoginGraceTime
The server disconnects after this time if the user has not
successfully logged in.
@ -1036,8 +1053,15 @@ The available criteria are
.Cm Host ,
.Cm LocalAddress ,
.Cm LocalPort ,
.Cm RDomain ,
and
.Cm Address .
.Cm Address
(with
.Cm RDomain
representing the
.Xr rdomain 4
on which the connection was received.)
.Pp
The match patterns may consist of single entries or comma-separated
lists and may use the wildcard and negation operators described in the
.Sx PATTERNS
@ -1100,6 +1124,7 @@ Available keywords are
.Cm PubkeyAuthentication ,
.Cm RekeyLimit ,
.Cm RevokedKeys ,
.Cm RDomain ,
.Cm StreamLocalBindMask ,
.Cm StreamLocalBindUnlink ,
.Cm TrustedUserCAKeys ,
@ -1188,7 +1213,6 @@ Specifies whether root can log in using
The argument must be
.Cm yes ,
.Cm prohibit-password ,
.Cm without-password ,
.Cm forced-commands-only ,
or
.Cm no .
@ -1197,8 +1221,8 @@ The default is
.Pp
If this option is set to
.Cm prohibit-password
or
.Cm without-password ,
(or its deprecated alias,
.Cm without-password ) ,
password and keyboard-interactive authentication are disabled for root.
.Pp
If this option is set to
@ -1361,6 +1385,15 @@ an OpenSSH Key Revocation List (KRL) as generated by
.Xr ssh-keygen 1 .
For more information on KRLs, see the KEY REVOCATION LISTS section in
.Xr ssh-keygen 1 .
.It Cm RDomain
Specifies an explicit routing domain that is applied after authentication
has completed.
The user session, as well and any forwarded or listening IP sockets,
will be bound to this
.Xr rdomain 4 .
If the routing domain is set to
.Cm \&%D ,
then the domain in which the incoming connection was received will be applied.
.It Cm StreamLocalBindMask
Sets the octal file creation mode mask
.Pq umask
@ -1626,6 +1659,8 @@ which are expanded at runtime:
.It %%
A literal
.Sq % .
.It \&%D
The routing domain in which the incoming connection was received.
.It %F
The fingerprint of the CA key.
.It %f
@ -1662,6 +1697,9 @@ accepts the tokens %%, %h, and %u.
.Pp
.Cm ChrootDirectory
accepts the tokens %%, %h, and %u.
.Pp
.Cm RoutingDomain
accepts the token %D.
.Sh FILES
.Bl -tag -width Ds
.It Pa /etc/ssh/sshd_config

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.c,v 1.56 2017/08/12 06:42:52 djm Exp $ */
/* $OpenBSD: sshkey.c,v 1.57 2017/10/13 06:24:51 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@ -3304,7 +3304,7 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob,
int blen, len = strlen(_passphrase);
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
const u_char *bptr;
char *bptr;
BIO *bio = NULL;
if (len > 0 && len <= 4)

106
umac.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: umac.c,v 1.12 2017/05/31 08:09:45 markus Exp $ */
/* $OpenBSD: umac.c,v 1.13 2017/10/27 01:01:17 djm Exp $ */
/* -----------------------------------------------------------------------
*
* umac.c -- C Implementation UMAC Message Authentication
@ -21,7 +21,7 @@
* Comments should be directed to Ted Krovetz (tdk@acm.org)
*
* ---------------------------------------------------------------------- */
/* ////////////////////// IMPORTANT NOTES /////////////////////////////////
*
* 1) This version does not work properly on messages larger than 16MB
@ -47,7 +47,7 @@
* produced under gcc with optimizations set -O3 or higher. Dunno why.
*
/////////////////////////////////////////////////////////////////////// */
/* ---------------------------------------------------------------------- */
/* --- User Switches ---------------------------------------------------- */
/* ---------------------------------------------------------------------- */
@ -187,11 +187,11 @@ static void kdf(void *bufp, aes_int_key key, UINT8 ndx, int nbytes)
UINT8 out_buf[AES_BLOCK_LEN];
UINT8 *dst_buf = (UINT8 *)bufp;
int i;
/* Setup the initial value */
in_buf[AES_BLOCK_LEN-9] = ndx;
in_buf[AES_BLOCK_LEN-1] = i = 1;
while (nbytes >= AES_BLOCK_LEN) {
aes_encryption(in_buf, out_buf, key);
memcpy(dst_buf,out_buf,AES_BLOCK_LEN);
@ -222,10 +222,10 @@ typedef struct {
static void pdf_init(pdf_ctx *pc, aes_int_key prf_key)
{
UINT8 buf[UMAC_KEY_LEN];
kdf(buf, prf_key, 0, UMAC_KEY_LEN);
aes_key_setup(buf, pc->prf_key);
/* Initialize pdf and cache */
memset(pc->nonce, 0, sizeof(pc->nonce));
aes_encryption(pc->nonce, pc->cache, pc->prf_key);
@ -238,7 +238,7 @@ static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8])
* of the AES output. If last time around we returned the ndx-1st
* element, then we may have the result in the cache already.
*/
#if (UMAC_OUTPUT_LEN == 4)
#define LOW_BIT_MASK 3
#elif (UMAC_OUTPUT_LEN == 8)
@ -255,7 +255,7 @@ static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8])
#endif
*(UINT32 *)t.tmp_nonce_lo = ((const UINT32 *)nonce)[1];
t.tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */
if ( (((UINT32 *)t.tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) ||
(((const UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) )
{
@ -263,7 +263,7 @@ static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8])
((UINT32 *)pc->nonce)[1] = ((UINT32 *)t.tmp_nonce_lo)[0];
aes_encryption(pc->nonce, pc->cache, pc->prf_key);
}
#if (UMAC_OUTPUT_LEN == 4)
*((UINT32 *)buf) ^= ((UINT32 *)pc->cache)[ndx];
#elif (UMAC_OUTPUT_LEN == 8)
@ -302,7 +302,7 @@ static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8])
* The routine nh_init() initializes the nh_ctx data structure and
* must be called once, before any other PDF routine.
*/
/* The "nh_aux" routines do the actual NH hashing work. They
* expect buffers to be multiples of L1_PAD_BOUNDARY. These routines
* produce output for all STREAMS NH iterations in one call,
@ -340,7 +340,7 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
const UINT32 *d = (const UINT32 *)dp;
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7;
h = *((UINT64 *)hp);
do {
d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
@ -353,7 +353,7 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
h += MUL64((k1 + d1), (k5 + d5));
h += MUL64((k2 + d2), (k6 + d6));
h += MUL64((k3 + d3), (k7 + d7));
d += 8;
k += 8;
} while (--c);
@ -421,7 +421,7 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
k8,k9,k10,k11,k12,k13,k14,k15;
h1 = *((UINT64 *)hp);
h2 = *((UINT64 *)hp + 1);
h3 = *((UINT64 *)hp + 2);
@ -434,26 +434,26 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
h1 += MUL64((k0 + d0), (k4 + d4));
h2 += MUL64((k4 + d0), (k8 + d4));
h3 += MUL64((k8 + d0), (k12 + d4));
h1 += MUL64((k1 + d1), (k5 + d5));
h2 += MUL64((k5 + d1), (k9 + d5));
h3 += MUL64((k9 + d1), (k13 + d5));
h1 += MUL64((k2 + d2), (k6 + d6));
h2 += MUL64((k6 + d2), (k10 + d6));
h3 += MUL64((k10 + d2), (k14 + d6));
h1 += MUL64((k3 + d3), (k7 + d7));
h2 += MUL64((k7 + d3), (k11 + d7));
h3 += MUL64((k11 + d3), (k15 + d7));
k0 = k8; k1 = k9; k2 = k10; k3 = k11;
k4 = k12; k5 = k13; k6 = k14; k7 = k15;
d += 8;
k += 8;
} while (--c);
@ -477,7 +477,7 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
k8,k9,k10,k11,k12,k13,k14,k15,
k16,k17,k18,k19;
h1 = *((UINT64 *)hp);
h2 = *((UINT64 *)hp + 1);
h3 = *((UINT64 *)hp + 2);
@ -492,31 +492,31 @@ static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen)
k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
k16 = *(k+16); k17 = *(k+17); k18 = *(k+18); k19 = *(k+19);
h1 += MUL64((k0 + d0), (k4 + d4));
h2 += MUL64((k4 + d0), (k8 + d4));
h3 += MUL64((k8 + d0), (k12 + d4));
h4 += MUL64((k12 + d0), (k16 + d4));
h1 += MUL64((k1 + d1), (k5 + d5));
h2 += MUL64((k5 + d1), (k9 + d5));
h3 += MUL64((k9 + d1), (k13 + d5));
h4 += MUL64((k13 + d1), (k17 + d5));
h1 += MUL64((k2 + d2), (k6 + d6));
h2 += MUL64((k6 + d2), (k10 + d6));
h3 += MUL64((k10 + d2), (k14 + d6));
h4 += MUL64((k14 + d2), (k18 + d6));
h1 += MUL64((k3 + d3), (k7 + d7));
h2 += MUL64((k7 + d3), (k11 + d7));
h3 += MUL64((k11 + d3), (k15 + d7));
h4 += MUL64((k15 + d3), (k19 + d7));
k0 = k8; k1 = k9; k2 = k10; k3 = k11;
k4 = k12; k5 = k13; k6 = k14; k7 = k15;
k8 = k16; k9 = k17; k10 = k18; k11 = k19;
d += 8;
k += 8;
} while (--c);
@ -541,7 +541,7 @@ static void nh_transform(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes)
*/
{
UINT8 *key;
key = hc->nh_key + hc->bytes_hashed;
nh_aux(key, buf, hc->state, nbytes);
}
@ -613,7 +613,7 @@ static void nh_update(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes)
/* even multiple of HASH_BUF_BYTES. */
{
UINT32 i,j;
j = hc->next_data_empty;
if ((j + nbytes) >= HASH_BUF_BYTES) {
if (j) {
@ -711,10 +711,10 @@ static void nh(nh_ctx *hc, const UINT8 *buf, UINT32 padded_len,
*/
{
UINT32 nbits;
/* Initialize the hash state */
nbits = (unpadded_len << 3);
((UINT64 *)result)[0] = nbits;
#if (UMAC_OUTPUT_LEN >= 8)
((UINT64 *)result)[1] = nbits;
@ -725,7 +725,7 @@ static void nh(nh_ctx *hc, const UINT8 *buf, UINT32 padded_len,
#if (UMAC_OUTPUT_LEN == 16)
((UINT64 *)result)[3] = nbits;
#endif
nh_aux(hc->nh_key, buf, result, padded_len);
}
@ -802,13 +802,13 @@ static UINT64 poly64(UINT64 cur, UINT64 key, UINT64 data)
x_lo,
x_hi;
UINT64 X,T,res;
X = MUL64(key_hi, cur_lo) + MUL64(cur_hi, key_lo);
x_lo = (UINT32)X;
x_hi = (UINT32)(X >> 32);
res = (MUL64(key_hi, cur_hi) + x_hi) * 59 + MUL64(key_lo, cur_lo);
T = ((UINT64)x_lo << 32);
res += T;
if (res < T)
@ -832,7 +832,7 @@ static void poly_hash(uhash_ctx_t hc, UINT32 data_in[])
{
int i;
UINT64 *data=(UINT64*)data_in;
for (i = 0; i < STREAMS; i++) {
if ((UINT32)(data[i] >> 32) == 0xfffffffful) {
hc->poly_accum[i] = poly64(hc->poly_accum[i],
@ -862,7 +862,7 @@ static UINT64 ip_aux(UINT64 t, UINT64 *ipkp, UINT64 data)
t = t + ipkp[1] * (UINT64)(UINT16)(data >> 32);
t = t + ipkp[2] * (UINT64)(UINT16)(data >> 16);
t = t + ipkp[3] * (UINT64)(UINT16)(data);
return t;
}
@ -870,7 +870,7 @@ static UINT32 ip_reduce_p36(UINT64 t)
{
/* Divisionless modular reduction */
UINT64 ret;
ret = (t & m36) + 5 * (t >> 36);
if (ret >= p36)
ret -= p36;
@ -888,7 +888,7 @@ static void ip_short(uhash_ctx_t ahc, UINT8 *nh_res, u_char *res)
{
UINT64 t;
UINT64 *nhp = (UINT64 *)nh_res;
t = ip_aux(0,ahc->ip_keys, nhp[0]);
STORE_UINT32_BIG((UINT32 *)res+0, ip_reduce_p36(t) ^ ahc->ip_trans[0]);
#if (UMAC_OUTPUT_LEN >= 8)
@ -958,13 +958,13 @@ static void uhash_init(uhash_ctx_t ahc, aes_int_key prf_key)
{
int i;
UINT8 buf[(8*STREAMS+4)*sizeof(UINT64)];
/* Zero the entire uhash context */
memset(ahc, 0, sizeof(uhash_ctx));
/* Initialize the L1 hash */
nh_init(&ahc->hash, prf_key);
/* Setup L2 hash variables */
kdf(buf, prf_key, 2, sizeof(buf)); /* Fill buffer with index 1 key */
for (i = 0; i < STREAMS; i++) {
@ -978,7 +978,7 @@ static void uhash_init(uhash_ctx_t ahc, aes_int_key prf_key)
ahc->poly_key_8[i] &= ((UINT64)0x01ffffffu << 32) + 0x01ffffffu;
ahc->poly_accum[i] = 1; /* Our polyhash prepends a non-zero word */
}
/* Setup L3-1 hash variables */
kdf(buf, prf_key, 3, sizeof(buf)); /* Fill buffer with index 2 key */
for (i = 0; i < STREAMS; i++)
@ -988,7 +988,7 @@ static void uhash_init(uhash_ctx_t ahc, aes_int_key prf_key)
sizeof(ahc->ip_keys));
for (i = 0; i < STREAMS*4; i++)
ahc->ip_keys[i] %= p36; /* Bring into Z_p36 */
/* Setup L3-2 hash variables */
/* Fill buffer with index 4 key */
kdf(ahc->ip_trans, prf_key, 4, STREAMS * sizeof(UINT32));
@ -1006,7 +1006,7 @@ static uhash_ctx_t uhash_alloc(u_char key[])
uhash_ctx_t ctx;
u_char bytes_to_add;
aes_int_key prf_key;
ctx = (uhash_ctx_t)malloc(sizeof(uhash_ctx)+ALLOC_BOUNDARY);
if (ctx) {
if (ALLOC_BOUNDARY) {
@ -1029,7 +1029,7 @@ static int uhash_free(uhash_ctx_t ctx)
{
/* Free memory allocated by uhash_alloc */
u_char bytes_to_sub;
if (ctx) {
if (ALLOC_BOUNDARY) {
bytes_to_sub = *((u_char *)ctx - 1);
@ -1050,12 +1050,12 @@ static int uhash_update(uhash_ctx_t ctx, const u_char *input, long len)
UWORD bytes_hashed, bytes_remaining;
UINT64 result_buf[STREAMS];
UINT8 *nh_result = (UINT8 *)&result_buf;
if (ctx->msg_len + len <= L1_KEY_LEN) {
nh_update(&ctx->hash, (const UINT8 *)input, len);
ctx->msg_len += len;
} else {
bytes_hashed = ctx->msg_len % L1_KEY_LEN;
if (ctx->msg_len == L1_KEY_LEN)
bytes_hashed = L1_KEY_LEN;
@ -1128,7 +1128,7 @@ static int uhash(uhash_ctx_t ahc, u_char *msg, long len, u_char *res)
UINT8 nh_result[STREAMS*sizeof(UINT64)];
UINT32 nh_len;
int extra_zeroes_needed;
/* If the message to be hashed is no longer than L1_HASH_LEN, we skip
* the polyhash.
*/
@ -1161,7 +1161,7 @@ static int uhash(uhash_ctx_t ahc, u_char *msg, long len, u_char *res)
ip_long(ahc, res);
}
uhash_reset(ahc);
return 1;
}
@ -1220,7 +1220,7 @@ struct umac_ctx *umac_new(const u_char key[])
struct umac_ctx *ctx, *octx;
size_t bytes_to_add;
aes_int_key prf_key;
octx = ctx = xcalloc(1, sizeof(*ctx) + ALLOC_BOUNDARY);
if (ctx) {
if (ALLOC_BOUNDARY) {
@ -1234,7 +1234,7 @@ struct umac_ctx *umac_new(const u_char key[])
uhash_init(&ctx->hash, prf_key);
explicit_bzero(prf_key, sizeof(prf_key));
}
return (ctx);
}
@ -1245,7 +1245,7 @@ int umac_final(struct umac_ctx *ctx, u_char tag[], const u_char nonce[8])
{
uhash_final(&ctx->hash, (u_char *)tag);
pdf_gen_xor(&ctx->pdf, (const UINT8 *)nonce, (UINT8 *)tag);
return (1);
}
@ -1270,7 +1270,7 @@ int umac(struct umac_ctx *ctx, u_char *input,
{
uhash(&ctx->hash, input, len, (u_char *)tag);
pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag);
return (1);
}
#endif