From 1e30483c8ad2c2f39445d4a4b6ab20c241e40593 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 22 Dec 2014 02:15:52 +0000 Subject: upstream commit adjust for new SHA256 key fingerprints and slightly-different MD5 hex fingerprint format --- regress/Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 3feb7a997..2905a0d0a 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,6 +1,6 @@ -# $OpenBSD: Makefile,v 1.70 2014/06/24 01:14:17 djm Exp $ +# $OpenBSD: Makefile,v 1.71 2014/12/22 02:15:52 djm Exp $ -REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t-exec +REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t-exec tests: $(REGRESS_TARGETS) # Interop tests are not run by default @@ -119,7 +119,7 @@ t3: ${TEST_SSH_SSHKEYGEN} -if $(OBJ)/t3.out | diff - ${.CURDIR}/rsa_openssh.pub t4: - ${TEST_SSH_SSHKEYGEN} -lf ${.CURDIR}/rsa_openssh.pub |\ + ${TEST_SSH_SSHKEYGEN} -E md5 -lf ${.CURDIR}/rsa_openssh.pub |\ awk '{print $$2}' | diff - ${.CURDIR}/t4.ok t5: @@ -164,6 +164,10 @@ t10: $(OBJ)/t10.out ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t10.out > /dev/null ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t10.out > /dev/null +t11: + ${TEST_SSH_SSHKEYGEN} -E sha256 -lf ${.CURDIR}/rsa_openssh.pub |\ + awk '{print $$2}' | diff - ${.CURDIR}/t11.ok + t-exec: ${LTESTS:=.sh} @if [ "x$?" = "x" ]; then exit 0; fi; \ for TEST in ""$?; do \ -- cgit v1.2.3 From 4bea0ab3290c0b9dd2aa199e932de8e7e18062d6 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 22 Dec 2014 08:06:03 +0000 Subject: upstream commit regression test for multiple required pubkey authentication; ok markus@ --- regress/Makefile | 5 ++-- regress/multipubkey.sh | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 regress/multipubkey.sh (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 2905a0d0a..27c4e79e1 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.71 2014/12/22 02:15:52 djm Exp $ +# $OpenBSD: Makefile,v 1.72 2014/12/22 08:06:03 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t-exec tests: $(REGRESS_TARGETS) @@ -64,7 +64,8 @@ LTESTS= connect \ keys-command \ forward-control \ integrity \ - krl + krl \ + multipubkey # dhgex \ INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers diff --git a/regress/multipubkey.sh b/regress/multipubkey.sh new file mode 100644 index 000000000..e9d15306f --- /dev/null +++ b/regress/multipubkey.sh @@ -0,0 +1,66 @@ +# $OpenBSD: multipubkey.sh,v 1.1 2014/12/22 08:06:03 djm Exp $ +# Placed in the Public Domain. + +tid="multiple pubkey" + +rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/user_key* +rm -f $OBJ/authorized_principals_$USER $OBJ/cert_user_key* + +mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig +mv $OBJ/ssh_proxy $OBJ/ssh_proxy.orig + +# Create a CA key +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_ca_key ||\ + fatal "ssh-keygen failed" + +# Make some keys and a certificate. +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key1 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key2 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -s $OBJ/user_ca_key -I "regress user key for $USER" \ + -z $$ -n ${USER},mekmitasdigoat $OBJ/user_key1 || + fail "couldn't sign user_key1" +# Copy the private key alongside the cert to allow better control of when +# it is offered. +mv $OBJ/user_key1-cert.pub $OBJ/cert_user_key1.pub +cp -p $OBJ/user_key1 $OBJ/cert_user_key1 + +grep -v IdentityFile $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy + +opts="-oProtocol=2 -F $OBJ/ssh_proxy -oIdentitiesOnly=yes" +opts="$opts -i $OBJ/cert_user_key1 -i $OBJ/user_key1 -i $OBJ/user_key2" + +for privsep in no yes; do + ( + grep -v "Protocol" $OBJ/sshd_proxy.orig + echo "Protocol 2" + echo "UsePrivilegeSeparation $privsep" + echo "AuthenticationMethods publickey,publickey" + echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" + echo "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" + ) > $OBJ/sshd_proxy + + # Single key should fail. + rm -f $OBJ/authorized_principals_$USER + cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER + ${SSH} $opts proxy true && fail "ssh succeeded with key" + + # Single key with same-public cert should fail. + echo mekmitasdigoat > $OBJ/authorized_principals_$USER + cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER + ${SSH} $opts proxy true && fail "ssh succeeded with key+cert" + + # Multiple plain keys should succeed. + rm -f $OBJ/authorized_principals_$USER + cat $OBJ/user_key1.pub $OBJ/user_key2.pub > \ + $OBJ/authorized_keys_$USER + ${SSH} $opts proxy true || fail "ssh failed with multiple keys" + # Cert and different key should succeed + + # Key and different-public cert should succeed. + echo mekmitasdigoat > $OBJ/authorized_principals_$USER + cat $OBJ/user_key2.pub > $OBJ/authorized_keys_$USER + ${SSH} $opts proxy true || fail "ssh failed with key/cert" +done + -- cgit v1.2.3 From 293cac52dcda123244b2e594d15592e5e481c55e Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 22 Dec 2014 16:30:42 +1100 Subject: include and use OpenBSD netcat in regress/ --- Makefile.in | 5 + regress/Makefile | 2 +- regress/multiplex.sh | 23 +- regress/netcat.c | 1638 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1649 insertions(+), 19 deletions(-) create mode 100644 regress/netcat.c (limited to 'regress/Makefile') diff --git a/Makefile.in b/Makefile.in index 06be3d5d5..9b485fba8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -436,6 +436,10 @@ regress/setuid-allowed$(EXEEXT): $(srcdir)/regress/setuid-allowed.c $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \ $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $? \ + $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + UNITTESTS_TEST_HELPER_OBJS=\ regress/unittests/test_helper/test_helper.o \ regress/unittests/test_helper/fuzz.o @@ -476,6 +480,7 @@ regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \ REGRESS_BINARIES=\ regress/modpipe$(EXEEXT) \ regress/setuid-allowed$(EXEEXT) \ + regress/netcat$(EXEEXT) \ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) diff --git a/regress/Makefile b/regress/Makefile index 27c4e79e1..ac1ee2d5f 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -92,7 +92,7 @@ CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ regress.log failed-regress.log ssh-log-wrapper.sh \ sftp-server.sh sftp-server.log sftp.log setuid-allowed \ data ed25519-agent ed25519-agent.pub key.ed25519-512 \ - key.ed25519-512.pub + key.ed25519-512.pub netcat SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} diff --git a/regress/multiplex.sh b/regress/multiplex.sh index c75dee900..617615355 100644 --- a/regress/multiplex.sh +++ b/regress/multiplex.sh @@ -5,20 +5,7 @@ CTL=/tmp/openssh.regress.ctl-sock.$$ tid="connection multiplexing" -if have_prog nc ; then - if nc -h 2>&1 | grep -- -N >/dev/null; then - NC="nc -N"; - elif nc -h 2>&1 | grep -- "-U.*Use UNIX" >/dev/null ; then - NC="nc" - else - echo "nc is incompatible" - fi -fi - -if test -z "$NC" ; then - echo "skipped (no compatible nc found)" - exit 0 -fi +NC=$OBJ/netcat trace "will use ProxyCommand $proxycmd" if config_defined DISABLE_FD_PASSING ; then @@ -90,20 +77,20 @@ cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}" rm -f ${COPY} verbose "test $tid: forward" trace "forward over TCP/IP and check result" -$NC -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} > /dev/null & +$NC -N -l 127.0.0.1 $((${PORT} + 1)) < ${DATA} > /dev/null & netcat_pid=$! ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L127.0.0.1:$((${PORT} + 2)):127.0.0.1:$((${PORT} + 1)) otherhost >>$TEST_SSH_LOGFILE 2>&1 -$NC -d 127.0.0.1 $((${PORT} + 2)) > ${COPY} < /dev/null +$NC 127.0.0.1 $((${PORT} + 2)) < /dev/null > ${COPY} cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" kill $netcat_pid 2>/dev/null rm -f ${COPY} $OBJ/unix-[123].fwd trace "forward over UNIX and check result" -$NC -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null & +$NC -N -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null & netcat_pid=$! ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 -$NC -d -U $OBJ/unix-3.fwd > ${COPY} < /dev/null +$NC -U $OBJ/unix-3.fwd < /dev/null > ${COPY} cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" kill $netcat_pid 2>/dev/null rm -f ${COPY} $OBJ/unix-[123].fwd diff --git a/regress/netcat.c b/regress/netcat.c new file mode 100644 index 000000000..c14d8164c --- /dev/null +++ b/regress/netcat.c @@ -0,0 +1,1638 @@ +/* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu Exp $ */ +/* + * Copyright (c) 2001 Eric Jackson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Re-written nc(1) for OpenBSD. Original implementation by + * *Hobbit* . + */ + +#include "includes.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atomicio.h" + +#ifndef SUN_LEN +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif + +#define PORT_MAX 65535 +#define PORT_MAX_LEN 6 +#define UNIX_DG_TMP_SOCKET_SIZE 19 + +#define POLL_STDIN 0 +#define POLL_NETOUT 1 +#define POLL_NETIN 2 +#define POLL_STDOUT 3 +#define BUFSIZE 16384 + +/* Command Line Options */ +int dflag; /* detached, no stdin */ +int Fflag; /* fdpass sock to stdout */ +unsigned int iflag; /* Interval Flag */ +int kflag; /* More than one connect */ +int lflag; /* Bind to local port */ +int Nflag; /* shutdown() network socket */ +int nflag; /* Don't do name look up */ +char *Pflag; /* Proxy username */ +char *pflag; /* Localport flag */ +int rflag; /* Random ports flag */ +char *sflag; /* Source Address */ +int tflag; /* Telnet Emulation */ +int uflag; /* UDP - Default to TCP */ +int vflag; /* Verbosity */ +int xflag; /* Socks proxy */ +int zflag; /* Port Scan Flag */ +int Dflag; /* sodebug */ +int Iflag; /* TCP receive buffer size */ +int Oflag; /* TCP send buffer size */ +int Sflag; /* TCP MD5 signature option */ +int Tflag = -1; /* IP Type of Service */ +int rtableid = -1; + +int timeout = -1; +int family = AF_UNSPEC; +char *portlist[PORT_MAX+1]; +char *unix_dg_tmp_socket; + +void atelnet(int, unsigned char *, unsigned int); +void build_ports(char *); +void help(void); +int local_listen(char *, char *, struct addrinfo); +void readwrite(int); +void fdpass(int nfd) __attribute__((noreturn)); +int remote_connect(const char *, const char *, struct addrinfo); +int timeout_connect(int, const struct sockaddr *, socklen_t); +int socks_connect(const char *, const char *, struct addrinfo, + const char *, const char *, struct addrinfo, int, const char *); +int udptest(int); +int unix_bind(char *); +int unix_connect(char *); +int unix_listen(char *); +void set_common_sockopts(int); +int map_tos(char *, int *); +void report_connect(const struct sockaddr *, socklen_t); +void usage(int); +ssize_t drainbuf(int, unsigned char *, size_t *); +ssize_t fillbuf(int, unsigned char *, size_t *); + +int +main(int argc, char *argv[]) +{ + int ch, s, ret, socksv; + char *host, *uport; + struct addrinfo hints; + struct servent *sv; + socklen_t len; + struct sockaddr_storage cliaddr; + char *proxy = NULL; + const char *errstr, *proxyhost = "", *proxyport = NULL; + struct addrinfo proxyhints; + char unix_dg_tmp_socket_buf[UNIX_DG_TMP_SOCKET_SIZE]; + + ret = 1; + s = 0; + socksv = 5; + host = NULL; + uport = NULL; + sv = NULL; + + while ((ch = getopt(argc, argv, + "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) { + switch (ch) { + case '4': + family = AF_INET; + break; + case '6': + family = AF_INET6; + break; + case 'U': + family = AF_UNIX; + break; + case 'X': + if (strcasecmp(optarg, "connect") == 0) + socksv = -1; /* HTTP proxy CONNECT */ + else if (strcmp(optarg, "4") == 0) + socksv = 4; /* SOCKS v.4 */ + else if (strcmp(optarg, "5") == 0) + socksv = 5; /* SOCKS v.5 */ + else + errx(1, "unsupported proxy protocol"); + break; + case 'd': + dflag = 1; + break; + case 'F': + Fflag = 1; + break; + case 'h': + help(); + break; + case 'i': + iflag = strtonum(optarg, 0, UINT_MAX, &errstr); + if (errstr) + errx(1, "interval %s: %s", errstr, optarg); + break; + case 'k': + kflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'N': + Nflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'P': + Pflag = optarg; + break; + case 'p': + pflag = optarg; + break; + case 'r': + rflag = 1; + break; + case 's': + sflag = optarg; + break; + case 't': + tflag = 1; + break; + case 'u': + uflag = 1; + break; +#ifdef SO_RTABLE + case 'V': + rtableid = (int)strtonum(optarg, 0, + RT_TABLEID_MAX, &errstr); + if (errstr) + errx(1, "rtable %s: %s", errstr, optarg); + break; +#endif + case 'v': + vflag = 1; + break; + case 'w': + timeout = strtonum(optarg, 0, INT_MAX / 1000, &errstr); + if (errstr) + errx(1, "timeout %s: %s", errstr, optarg); + timeout *= 1000; + break; + case 'x': + xflag = 1; + if ((proxy = strdup(optarg)) == NULL) + err(1, NULL); + break; + case 'z': + zflag = 1; + break; + case 'D': + Dflag = 1; + break; + case 'I': + Iflag = strtonum(optarg, 1, 65536 << 14, &errstr); + if (errstr != NULL) + errx(1, "TCP receive window %s: %s", + errstr, optarg); + break; + case 'O': + Oflag = strtonum(optarg, 1, 65536 << 14, &errstr); + if (errstr != NULL) + errx(1, "TCP send window %s: %s", + errstr, optarg); + break; + case 'S': + Sflag = 1; + break; + case 'T': + errstr = NULL; + errno = 0; + if (map_tos(optarg, &Tflag)) + break; + if (strlen(optarg) > 1 && optarg[0] == '0' && + optarg[1] == 'x') + Tflag = (int)strtol(optarg, NULL, 16); + else + Tflag = (int)strtonum(optarg, 0, 255, + &errstr); + if (Tflag < 0 || Tflag > 255 || errstr || errno) + errx(1, "illegal tos value %s", optarg); + break; + default: + usage(1); + } + } + argc -= optind; + argv += optind; + + /* Cruft to make sure options are clean, and used properly. */ + if (argv[0] && !argv[1] && family == AF_UNIX) { + host = argv[0]; + uport = NULL; + } else if (argv[0] && !argv[1]) { + if (!lflag) + usage(1); + uport = argv[0]; + host = NULL; + } else if (argv[0] && argv[1]) { + host = argv[0]; + uport = argv[1]; + } else + usage(1); + + if (lflag && sflag) + errx(1, "cannot use -s and -l"); + if (lflag && pflag) + errx(1, "cannot use -p and -l"); + if (lflag && zflag) + errx(1, "cannot use -z and -l"); + if (!lflag && kflag) + errx(1, "must use -l with -k"); + + /* Get name of temporary socket for unix datagram client */ + if ((family == AF_UNIX) && uflag && !lflag) { + if (sflag) { + unix_dg_tmp_socket = sflag; + } else { + strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX", + UNIX_DG_TMP_SOCKET_SIZE); + if (mktemp(unix_dg_tmp_socket_buf) == NULL) + err(1, "mktemp"); + unix_dg_tmp_socket = unix_dg_tmp_socket_buf; + } + } + + /* Initialize addrinfo structure. */ + if (family != AF_UNIX) { + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; + if (nflag) + hints.ai_flags |= AI_NUMERICHOST; + } + + if (xflag) { + if (uflag) + errx(1, "no proxy support for UDP mode"); + + if (lflag) + errx(1, "no proxy support for listen"); + + if (family == AF_UNIX) + errx(1, "no proxy support for unix sockets"); + + /* XXX IPv6 transport to proxy would probably work */ + if (family == AF_INET6) + errx(1, "no proxy support for IPv6"); + + if (sflag) + errx(1, "no proxy support for local source address"); + + proxyhost = strsep(&proxy, ":"); + proxyport = proxy; + + memset(&proxyhints, 0, sizeof(struct addrinfo)); + proxyhints.ai_family = family; + proxyhints.ai_socktype = SOCK_STREAM; + proxyhints.ai_protocol = IPPROTO_TCP; + if (nflag) + proxyhints.ai_flags |= AI_NUMERICHOST; + } + + if (lflag) { + int connfd; + ret = 0; + + if (family == AF_UNIX) { + if (uflag) + s = unix_bind(host); + else + s = unix_listen(host); + } + + /* Allow only one connection at a time, but stay alive. */ + for (;;) { + if (family != AF_UNIX) + s = local_listen(host, uport, hints); + if (s < 0) + err(1, NULL); + /* + * For UDP and -k, don't connect the socket, let it + * receive datagrams from multiple socket pairs. + */ + if (uflag && kflag) + readwrite(s); + /* + * For UDP and not -k, we will use recvfrom() initially + * to wait for a caller, then use the regular functions + * to talk to the caller. + */ + else if (uflag && !kflag) { + int rv, plen; + char buf[16384]; + struct sockaddr_storage z; + + len = sizeof(z); + plen = 2048; + rv = recvfrom(s, buf, plen, MSG_PEEK, + (struct sockaddr *)&z, &len); + if (rv < 0) + err(1, "recvfrom"); + + rv = connect(s, (struct sockaddr *)&z, len); + if (rv < 0) + err(1, "connect"); + + if (vflag) + report_connect((struct sockaddr *)&z, len); + + readwrite(s); + } else { + len = sizeof(cliaddr); + connfd = accept(s, (struct sockaddr *)&cliaddr, + &len); + if (connfd == -1) { + /* For now, all errnos are fatal */ + err(1, "accept"); + } + if (vflag) + report_connect((struct sockaddr *)&cliaddr, len); + + readwrite(connfd); + close(connfd); + } + + if (family != AF_UNIX) + close(s); + else if (uflag) { + if (connect(s, NULL, 0) < 0) + err(1, "connect"); + } + + if (!kflag) + break; + } + } else if (family == AF_UNIX) { + ret = 0; + + if ((s = unix_connect(host)) > 0 && !zflag) { + readwrite(s); + close(s); + } else + ret = 1; + + if (uflag) + unlink(unix_dg_tmp_socket); + exit(ret); + + } else { + int i = 0; + + /* Construct the portlist[] array. */ + build_ports(uport); + + /* Cycle through portlist, connecting to each port. */ + for (i = 0; portlist[i] != NULL; i++) { + if (s) + close(s); + + if (xflag) + s = socks_connect(host, portlist[i], hints, + proxyhost, proxyport, proxyhints, socksv, + Pflag); + else + s = remote_connect(host, portlist[i], hints); + + if (s < 0) + continue; + + ret = 0; + if (vflag || zflag) { + /* For UDP, make sure we are connected. */ + if (uflag) { + if (udptest(s) == -1) { + ret = 1; + continue; + } + } + + /* Don't look up port if -n. */ + if (nflag) + sv = NULL; + else { + sv = getservbyport( + ntohs(atoi(portlist[i])), + uflag ? "udp" : "tcp"); + } + + fprintf(stderr, + "Connection to %s %s port [%s/%s] " + "succeeded!\n", host, portlist[i], + uflag ? "udp" : "tcp", + sv ? sv->s_name : "*"); + } + if (Fflag) + fdpass(s); + else if (!zflag) + readwrite(s); + } + } + + if (s) + close(s); + + exit(ret); +} + +/* + * unix_bind() + * Returns a unix socket bound to the given path + */ +int +unix_bind(char *path) +{ + struct sockaddr_un sun; + int s; + + /* Create unix domain socket. */ + if ((s = socket(AF_UNIX, uflag ? SOCK_DGRAM : SOCK_STREAM, + 0)) < 0) + return (-1); + + memset(&sun, 0, sizeof(struct sockaddr_un)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) { + close(s); + errno = ENAMETOOLONG; + return (-1); + } + + if (bind(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { + close(s); + return (-1); + } + return (s); +} + +/* + * unix_connect() + * Returns a socket connected to a local unix socket. Returns -1 on failure. + */ +int +unix_connect(char *path) +{ + struct sockaddr_un sun; + int s; + + if (uflag) { + if ((s = unix_bind(unix_dg_tmp_socket)) < 0) + return (-1); + } else { + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return (-1); + } + (void)fcntl(s, F_SETFD, FD_CLOEXEC); + + memset(&sun, 0, sizeof(struct sockaddr_un)); + sun.sun_family = AF_UNIX; + + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) { + close(s); + errno = ENAMETOOLONG; + return (-1); + } + if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) { + close(s); + return (-1); + } + return (s); + +} + +/* + * unix_listen() + * Create a unix domain socket, and listen on it. + */ +int +unix_listen(char *path) +{ + int s; + if ((s = unix_bind(path)) < 0) + return (-1); + + if (listen(s, 5) < 0) { + close(s); + return (-1); + } + return (s); +} + +/* + * remote_connect() + * Returns a socket connected to a remote host. Properly binds to a local + * port or source address if needed. Returns -1 on failure. + */ +int +remote_connect(const char *host, const char *port, struct addrinfo hints) +{ + struct addrinfo *res, *res0; + int s, error; +#ifdef SO_RTABLE + int on = 1; +#endif + + if ((error = getaddrinfo(host, port, &hints, &res))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + res0 = res; + do { + if ((s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol)) < 0) + continue; + +#ifdef SO_RTABLE + if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, + &rtableid, sizeof(rtableid)) == -1)) + err(1, "setsockopt SO_RTABLE"); +#endif + /* Bind to a local port or source address if specified. */ + if (sflag || pflag) { + struct addrinfo ahints, *ares; + +#ifdef SO_BINDANY + /* try SO_BINDANY, but don't insist */ + setsockopt(s, SOL_SOCKET, SO_BINDANY, &on, sizeof(on)); +#endif + memset(&ahints, 0, sizeof(struct addrinfo)); + ahints.ai_family = res0->ai_family; + ahints.ai_socktype = uflag ? SOCK_DGRAM : SOCK_STREAM; + ahints.ai_protocol = uflag ? IPPROTO_UDP : IPPROTO_TCP; + ahints.ai_flags = AI_PASSIVE; + if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + if (bind(s, (struct sockaddr *)ares->ai_addr, + ares->ai_addrlen) < 0) + err(1, "bind failed"); + freeaddrinfo(ares); + } + + set_common_sockopts(s); + + if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) + break; + else if (vflag) + warn("connect to %s port %s (%s) failed", host, port, + uflag ? "udp" : "tcp"); + + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + + freeaddrinfo(res); + + return (s); +} + +int +timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct pollfd pfd; + socklen_t optlen; + int flags = 0, optval; + int ret; + + if (timeout != -1) { + flags = fcntl(s, F_GETFL, 0); + if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) + err(1, "set non-blocking mode"); + } + + if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { + pfd.fd = s; + pfd.events = POLLOUT; + if ((ret = poll(&pfd, 1, timeout)) == 1) { + optlen = sizeof(optval); + if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, + &optval, &optlen)) == 0) { + errno = optval; + ret = optval == 0 ? 0 : -1; + } + } else if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + } else + err(1, "poll failed"); + } + + if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) + err(1, "restoring flags"); + + return (ret); +} + +/* + * local_listen() + * Returns a socket listening on a local port, binds to specified source + * address. Returns -1 on failure. + */ +int +local_listen(char *host, char *port, struct addrinfo hints) +{ + struct addrinfo *res, *res0; + int s, ret, x = 1; + int error; + + /* Allow nodename to be null. */ + hints.ai_flags |= AI_PASSIVE; + + /* + * In the case of binding to a wildcard address + * default to binding to an ipv4 address. + */ + if (host == NULL && hints.ai_family == AF_UNSPEC) + hints.ai_family = AF_INET; + + if ((error = getaddrinfo(host, port, &hints, &res))) + errx(1, "getaddrinfo: %s", gai_strerror(error)); + + res0 = res; + do { + if ((s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol)) < 0) + continue; + +#ifdef SO_RTABLE + if (rtableid >= 0 && (setsockopt(s, SOL_SOCKET, SO_RTABLE, + &rtableid, sizeof(rtableid)) == -1)) + err(1, "setsockopt SO_RTABLE"); +#endif + + ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); + if (ret == -1) + err(1, NULL); + + set_common_sockopts(s); + + if (bind(s, (struct sockaddr *)res0->ai_addr, + res0->ai_addrlen) == 0) + break; + + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + + if (!uflag && s != -1) { + if (listen(s, 1) < 0) + err(1, "listen"); + } + + freeaddrinfo(res); + + return (s); +} + +/* + * readwrite() + * Loop that polls on the network file descriptor and stdin. + */ +void +readwrite(int net_fd) +{ + struct pollfd pfd[4]; + int stdin_fd = STDIN_FILENO; + int stdout_fd = STDOUT_FILENO; + unsigned char netinbuf[BUFSIZE]; + size_t netinbufpos = 0; + unsigned char stdinbuf[BUFSIZE]; + size_t stdinbufpos = 0; + int n, num_fds; + ssize_t ret; + + /* don't read from stdin if requested */ + if (dflag) + stdin_fd = -1; + + /* stdin */ + pfd[POLL_STDIN].fd = stdin_fd; + pfd[POLL_STDIN].events = POLLIN; + + /* network out */ + pfd[POLL_NETOUT].fd = net_fd; + pfd[POLL_NETOUT].events = 0; + + /* network in */ + pfd[POLL_NETIN].fd = net_fd; + pfd[POLL_NETIN].events = POLLIN; + + /* stdout */ + pfd[POLL_STDOUT].fd = stdout_fd; + pfd[POLL_STDOUT].events = 0; + + while (1) { + /* both inputs are gone, buffers are empty, we are done */ + if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1 + && stdinbufpos == 0 && netinbufpos == 0) { + close(net_fd); + return; + } + /* both outputs are gone, we can't continue */ + if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) { + close(net_fd); + return; + } + /* listen and net in gone, queues empty, done */ + if (lflag && pfd[POLL_NETIN].fd == -1 + && stdinbufpos == 0 && netinbufpos == 0) { + close(net_fd); + return; + } + + /* help says -i is for "wait between lines sent". We read and + * write arbitrary amounts of data, and we don't want to start + * scanning for newlines, so this is as good as it gets */ + if (iflag) + sleep(iflag); + + /* poll */ + num_fds = poll(pfd, 4, timeout); + + /* treat poll errors */ + if (num_fds == -1) { + close(net_fd); + err(1, "polling error"); + } + + /* timeout happened */ + if (num_fds == 0) + return; + + /* treat socket error conditions */ + for (n = 0; n < 4; n++) { + if (pfd[n].revents & (POLLERR|POLLNVAL)) { + pfd[n].fd = -1; + } + } + /* reading is possible after HUP */ + if (pfd[POLL_STDIN].events & POLLIN && + pfd[POLL_STDIN].revents & POLLHUP && + ! (pfd[POLL_STDIN].revents & POLLIN)) + pfd[POLL_STDIN].fd = -1; + + if (pfd[POLL_NETIN].events & POLLIN && + pfd[POLL_NETIN].revents & POLLHUP && + ! (pfd[POLL_NETIN].revents & POLLIN)) + pfd[POLL_NETIN].fd = -1; + + if (pfd[POLL_NETOUT].revents & POLLHUP) { + if (Nflag) + shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); + pfd[POLL_NETOUT].fd = -1; + } + /* if HUP, stop watching stdout */ + if (pfd[POLL_STDOUT].revents & POLLHUP) + pfd[POLL_STDOUT].fd = -1; + /* if no net out, stop watching stdin */ + if (pfd[POLL_NETOUT].fd == -1) + pfd[POLL_STDIN].fd = -1; + /* if no stdout, stop watching net in */ + if (pfd[POLL_STDOUT].fd == -1) { + if (pfd[POLL_NETIN].fd != -1) + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; + } + + /* try to read from stdin */ + if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) { + ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf, + &stdinbufpos); + /* error or eof on stdin - remove from pfd */ + if (ret == 0 || ret == -1) + pfd[POLL_STDIN].fd = -1; + /* read something - poll net out */ + if (stdinbufpos > 0) + pfd[POLL_NETOUT].events = POLLOUT; + /* filled buffer - remove self from polling */ + if (stdinbufpos == BUFSIZE) + pfd[POLL_STDIN].events = 0; + } + /* try to write to network */ + if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) { + ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf, + &stdinbufpos); + if (ret == -1) + pfd[POLL_NETOUT].fd = -1; + /* buffer empty - remove self from polling */ + if (stdinbufpos == 0) + pfd[POLL_NETOUT].events = 0; + /* buffer no longer full - poll stdin again */ + if (stdinbufpos < BUFSIZE) + pfd[POLL_STDIN].events = POLLIN; + } + /* try to read from network */ + if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) { + ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf, + &netinbufpos); + if (ret == -1) + pfd[POLL_NETIN].fd = -1; + /* eof on net in - remove from pfd */ + if (ret == 0) { + shutdown(pfd[POLL_NETIN].fd, SHUT_RD); + pfd[POLL_NETIN].fd = -1; + } + /* read something - poll stdout */ + if (netinbufpos > 0) + pfd[POLL_STDOUT].events = POLLOUT; + /* filled buffer - remove self from polling */ + if (netinbufpos == BUFSIZE) + pfd[POLL_NETIN].events = 0; + /* handle telnet */ + if (tflag) + atelnet(pfd[POLL_NETIN].fd, netinbuf, + netinbufpos); + } + /* try to write to stdout */ + if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) { + ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf, + &netinbufpos); + if (ret == -1) + pfd[POLL_STDOUT].fd = -1; + /* buffer empty - remove self from polling */ + if (netinbufpos == 0) + pfd[POLL_STDOUT].events = 0; + /* buffer no longer full - poll net in again */ + if (netinbufpos < BUFSIZE) + pfd[POLL_NETIN].events = POLLIN; + } + + /* stdin gone and queue empty? */ + if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) { + if (pfd[POLL_NETOUT].fd != -1 && Nflag) + shutdown(pfd[POLL_NETOUT].fd, SHUT_WR); + pfd[POLL_NETOUT].fd = -1; + } + /* net in gone and queue empty? */ + if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) { + pfd[POLL_STDOUT].fd = -1; + } + } +} + +ssize_t +drainbuf(int fd, unsigned char *buf, size_t *bufpos) +{ + ssize_t n; + ssize_t adjust; + + n = write(fd, buf, *bufpos); + /* don't treat EAGAIN, EINTR as error */ + if (n == -1 && (errno == EAGAIN || errno == EINTR)) + n = -2; + if (n <= 0) + return n; + /* adjust buffer */ + adjust = *bufpos - n; + if (adjust > 0) + memmove(buf, buf + n, adjust); + *bufpos -= n; + return n; +} + + +ssize_t +fillbuf(int fd, unsigned char *buf, size_t *bufpos) +{ + size_t num = BUFSIZE - *bufpos; + ssize_t n; + + n = read(fd, buf + *bufpos, num); + /* don't treat EAGAIN, EINTR as error */ + if (n == -1 && (errno == EAGAIN || errno == EINTR)) + n = -2; + if (n <= 0) + return n; + *bufpos += n; + return n; +} + +/* + * fdpass() + * Pass the connected file descriptor to stdout and exit. + */ +void +fdpass(int nfd) +{ + struct msghdr mh; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; + struct iovec iov; + char c = '\0'; + ssize_t r; + struct pollfd pfd; + + /* Avoid obvious stupidity */ + if (isatty(STDOUT_FILENO)) + errx(1, "Cannot pass file descriptor to tty"); + + bzero(&mh, sizeof(mh)); + bzero(&cmsgbuf, sizeof(cmsgbuf)); + bzero(&iov, sizeof(iov)); + bzero(&pfd, sizeof(pfd)); + + mh.msg_control = (caddr_t)&cmsgbuf.buf; + mh.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = nfd; + + iov.iov_base = &c; + iov.iov_len = 1; + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + + bzero(&pfd, sizeof(pfd)); + pfd.fd = STDOUT_FILENO; + for (;;) { + r = sendmsg(STDOUT_FILENO, &mh, 0); + if (r == -1) { + if (errno == EAGAIN || errno == EINTR) { + pfd.events = POLLOUT; + if (poll(&pfd, 1, -1) == -1) + err(1, "poll"); + continue; + } + err(1, "sendmsg"); + } else if (r == -1) + errx(1, "sendmsg: unexpected return value %zd", r); + else + break; + } + exit(0); +} + +/* Deal with RFC 854 WILL/WONT DO/DONT negotiation. */ +void +atelnet(int nfd, unsigned char *buf, unsigned int size) +{ + unsigned char *p, *end; + unsigned char obuf[4]; + + if (size < 3) + return; + end = buf + size - 2; + + for (p = buf; p < end; p++) { + if (*p != IAC) + continue; + + obuf[0] = IAC; + p++; + if ((*p == WILL) || (*p == WONT)) + obuf[1] = DONT; + else if ((*p == DO) || (*p == DONT)) + obuf[1] = WONT; + else + continue; + + p++; + obuf[2] = *p; + if (atomicio(vwrite, nfd, obuf, 3) != 3) + warn("Write Error!"); + } +} + +/* + * build_ports() + * Build an array of ports in portlist[], listing each port + * that we should try to connect to. + */ +void +build_ports(char *p) +{ + const char *errstr; + char *n; + int hi, lo, cp; + int x = 0; + + if ((n = strchr(p, '-')) != NULL) { + *n = '\0'; + n++; + + /* Make sure the ports are in order: lowest->highest. */ + hi = strtonum(n, 1, PORT_MAX, &errstr); + if (errstr) + errx(1, "port number %s: %s", errstr, n); + lo = strtonum(p, 1, PORT_MAX, &errstr); + if (errstr) + errx(1, "port number %s: %s", errstr, p); + + if (lo > hi) { + cp = hi; + hi = lo; + lo = cp; + } + + /* Load ports sequentially. */ + for (cp = lo; cp <= hi; cp++) { + portlist[x] = calloc(1, PORT_MAX_LEN); + if (portlist[x] == NULL) + err(1, NULL); + snprintf(portlist[x], PORT_MAX_LEN, "%d", cp); + x++; + } + + /* Randomly swap ports. */ + if (rflag) { + int y; + char *c; + + for (x = 0; x <= (hi - lo); x++) { + y = (arc4random() & 0xFFFF) % (hi - lo); + c = portlist[x]; + portlist[x] = portlist[y]; + portlist[y] = c; + } + } + } else { + hi = strtonum(p, 1, PORT_MAX, &errstr); + if (errstr) + errx(1, "port number %s: %s", errstr, p); + portlist[0] = strdup(p); + if (portlist[0] == NULL) + err(1, NULL); + } +} + +/* + * udptest() + * Do a few writes to see if the UDP port is there. + * Fails once PF state table is full. + */ +int +udptest(int s) +{ + int i, ret; + + for (i = 0; i <= 3; i++) { + if (write(s, "X", 1) == 1) + ret = 1; + else + ret = -1; + } + return (ret); +} + +void +set_common_sockopts(int s) +{ + int x = 1; + + if (Sflag) { + if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, + &x, sizeof(x)) == -1) + err(1, NULL); + } + if (Dflag) { + if (setsockopt(s, SOL_SOCKET, SO_DEBUG, + &x, sizeof(x)) == -1) + err(1, NULL); + } + if (Tflag != -1) { + if (setsockopt(s, IPPROTO_IP, IP_TOS, + &Tflag, sizeof(Tflag)) == -1) + err(1, "set IP ToS"); + } + if (Iflag) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, + &Iflag, sizeof(Iflag)) == -1) + err(1, "set TCP receive buffer size"); + } + if (Oflag) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, + &Oflag, sizeof(Oflag)) == -1) + err(1, "set TCP send buffer size"); + } +} + +int +map_tos(char *s, int *val) +{ + /* DiffServ Codepoints and other TOS mappings */ + const struct toskeywords { + const char *keyword; + int val; + } *t, toskeywords[] = { + { "af11", IPTOS_DSCP_AF11 }, + { "af12", IPTOS_DSCP_AF12 }, + { "af13", IPTOS_DSCP_AF13 }, + { "af21", IPTOS_DSCP_AF21 }, + { "af22", IPTOS_DSCP_AF22 }, + { "af23", IPTOS_DSCP_AF23 }, + { "af31", IPTOS_DSCP_AF31 }, + { "af32", IPTOS_DSCP_AF32 }, + { "af33", IPTOS_DSCP_AF33 }, + { "af41", IPTOS_DSCP_AF41 }, + { "af42", IPTOS_DSCP_AF42 }, + { "af43", IPTOS_DSCP_AF43 }, + { "critical", IPTOS_PREC_CRITIC_ECP }, + { "cs0", IPTOS_DSCP_CS0 }, + { "cs1", IPTOS_DSCP_CS1 }, + { "cs2", IPTOS_DSCP_CS2 }, + { "cs3", IPTOS_DSCP_CS3 }, + { "cs4", IPTOS_DSCP_CS4 }, + { "cs5", IPTOS_DSCP_CS5 }, + { "cs6", IPTOS_DSCP_CS6 }, + { "cs7", IPTOS_DSCP_CS7 }, + { "ef", IPTOS_DSCP_EF }, + { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, + { "lowdelay", IPTOS_LOWDELAY }, + { "netcontrol", IPTOS_PREC_NETCONTROL }, + { "reliability", IPTOS_RELIABILITY }, + { "throughput", IPTOS_THROUGHPUT }, + { NULL, -1 }, + }; + + for (t = toskeywords; t->keyword != NULL; t++) { + if (strcmp(s, t->keyword) == 0) { + *val = t->val; + return (1); + } + } + + return (0); +} + +void +report_connect(const struct sockaddr *sa, socklen_t salen) +{ + char remote_host[NI_MAXHOST]; + char remote_port[NI_MAXSERV]; + int herr; + int flags = NI_NUMERICSERV; + + if (nflag) + flags |= NI_NUMERICHOST; + + if ((herr = getnameinfo(sa, salen, + remote_host, sizeof(remote_host), + remote_port, sizeof(remote_port), + flags)) != 0) { + if (herr == EAI_SYSTEM) + err(1, "getnameinfo"); + else + errx(1, "getnameinfo: %s", gai_strerror(herr)); + } + + fprintf(stderr, + "Connection from %s %s " + "received!\n", remote_host, remote_port); +} + +void +help(void) +{ + usage(0); + fprintf(stderr, "\tCommand Summary:\n\ + \t-4 Use IPv4\n\ + \t-6 Use IPv6\n\ + \t-D Enable the debug socket option\n\ + \t-d Detach from stdin\n\ + \t-F Pass socket fd\n\ + \t-h This help text\n\ + \t-I length TCP receive buffer length\n\ + \t-i secs\t Delay interval for lines sent, ports scanned\n\ + \t-k Keep inbound sockets open for multiple connects\n\ + \t-l Listen mode, for inbound connects\n\ + \t-N Shutdown the network socket after EOF on stdin\n\ + \t-n Suppress name/port resolutions\n\ + \t-O length TCP send buffer length\n\ + \t-P proxyuser\tUsername for proxy authentication\n\ + \t-p port\t Specify local port for remote connects\n\ + \t-r Randomize remote ports\n\ + \t-S Enable the TCP MD5 signature option\n\ + \t-s addr\t Local source address\n\ + \t-T toskeyword\tSet IP Type of Service\n\ + \t-t Answer TELNET negotiation\n\ + \t-U Use UNIX domain socket\n\ + \t-u UDP mode\n\ + \t-V rtable Specify alternate routing table\n\ + \t-v Verbose\n\ + \t-w secs\t Timeout for connects and final net reads\n\ + \t-X proto Proxy protocol: \"4\", \"5\" (SOCKS) or \"connect\"\n\ + \t-x addr[:port]\tSpecify proxy address and port\n\ + \t-z Zero-I/O mode [used for scanning]\n\ + Port numbers can be individual or ranges: lo-hi [inclusive]\n"); + exit(1); +} + +void +usage(int ret) +{ + fprintf(stderr, + "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" + "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" + "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" + "\t [-x proxy_address[:port]] [destination] [port]\n"); + if (ret) + exit(1); +} + +/* *** src/usr.bin/nc/socks.c *** */ + + +/* $OpenBSD: socks.c,v 1.20 2012/03/08 09:56:28 espie Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2004, 2005 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKS_PORT "1080" +#define HTTP_PROXY_PORT "3128" +#define HTTP_MAXHDRS 64 +#define SOCKS_V5 5 +#define SOCKS_V4 4 +#define SOCKS_NOAUTH 0 +#define SOCKS_NOMETHOD 0xff +#define SOCKS_CONNECT 1 +#define SOCKS_IPV4 1 +#define SOCKS_DOMAIN 3 +#define SOCKS_IPV6 4 + +int remote_connect(const char *, const char *, struct addrinfo); +int socks_connect(const char *, const char *, struct addrinfo, + const char *, const char *, struct addrinfo, int, + const char *); + +static int +decode_addrport(const char *h, const char *p, struct sockaddr *addr, + socklen_t addrlen, int v4only, int numeric) +{ + int r; + struct addrinfo hints, *res; + + bzero(&hints, sizeof(hints)); + hints.ai_family = v4only ? PF_INET : PF_UNSPEC; + hints.ai_flags = numeric ? AI_NUMERICHOST : 0; + hints.ai_socktype = SOCK_STREAM; + r = getaddrinfo(h, p, &hints, &res); + /* Don't fatal when attempting to convert a numeric address */ + if (r != 0) { + if (!numeric) { + errx(1, "getaddrinfo(\"%.64s\", \"%.64s\"): %s", h, p, + gai_strerror(r)); + } + return (-1); + } + if (addrlen < res->ai_addrlen) { + freeaddrinfo(res); + errx(1, "internal error: addrlen < res->ai_addrlen"); + } + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return (0); +} + +static int +proxy_read_line(int fd, char *buf, size_t bufsz) +{ + size_t off; + + for(off = 0;;) { + if (off >= bufsz) + errx(1, "proxy read too long"); + if (atomicio(read, fd, buf + off, 1) != 1) + err(1, "proxy read"); + /* Skip CR */ + if (buf[off] == '\r') + continue; + if (buf[off] == '\n') { + buf[off] = '\0'; + break; + } + off++; + } + return (off); +} + +static const char * +getproxypass(const char *proxyuser, const char *proxyhost) +{ + char prompt[512]; + static char pw[256]; + + snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ", + proxyuser, proxyhost); + if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL) + errx(1, "Unable to read proxy passphrase"); + return (pw); +} + +int +socks_connect(const char *host, const char *port, + struct addrinfo hints __attribute__ ((__unused__)), + const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, + int socksv, const char *proxyuser) +{ + int proxyfd, r, authretry = 0; + size_t hlen, wlen; + unsigned char buf[1024]; + size_t cnt; + struct sockaddr_storage addr; + struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; + in_port_t serverport; + const char *proxypass = NULL; + + if (proxyport == NULL) + proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; + + /* Abuse API to lookup port */ + if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, + sizeof(addr), 1, 1) == -1) + errx(1, "unknown port \"%.64s\"", port); + serverport = in4->sin_port; + + again: + if (authretry++ > 3) + errx(1, "Too many authentication failures"); + + proxyfd = remote_connect(proxyhost, proxyport, proxyhints); + + if (proxyfd < 0) + return (-1); + + if (socksv == 5) { + if (decode_addrport(host, port, (struct sockaddr *)&addr, + sizeof(addr), 0, 1) == -1) + addr.ss_family = 0; /* used in switch below */ + + /* Version 5, one method: no authentication */ + buf[0] = SOCKS_V5; + buf[1] = 1; + buf[2] = SOCKS_NOAUTH; + cnt = atomicio(vwrite, proxyfd, buf, 3); + if (cnt != 3) + err(1, "write failed (%zu/3)", cnt); + + cnt = atomicio(read, proxyfd, buf, 2); + if (cnt != 2) + err(1, "read failed (%zu/3)", cnt); + + if (buf[1] == SOCKS_NOMETHOD) + errx(1, "authentication method negotiation failed"); + + switch (addr.ss_family) { + case 0: + /* Version 5, connect: domain name */ + + /* Max domain name length is 255 bytes */ + hlen = strlen(host); + if (hlen > 255) + errx(1, "host name too long for SOCKS5"); + buf[0] = SOCKS_V5; + buf[1] = SOCKS_CONNECT; + buf[2] = 0; + buf[3] = SOCKS_DOMAIN; + buf[4] = hlen; + memcpy(buf + 5, host, hlen); + memcpy(buf + 5 + hlen, &serverport, sizeof serverport); + wlen = 7 + hlen; + break; + case AF_INET: + /* Version 5, connect: IPv4 address */ + buf[0] = SOCKS_V5; + buf[1] = SOCKS_CONNECT; + buf[2] = 0; + buf[3] = SOCKS_IPV4; + memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); + memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port); + wlen = 10; + break; + case AF_INET6: + /* Version 5, connect: IPv6 address */ + buf[0] = SOCKS_V5; + buf[1] = SOCKS_CONNECT; + buf[2] = 0; + buf[3] = SOCKS_IPV6; + memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr); + memcpy(buf + 20, &in6->sin6_port, + sizeof in6->sin6_port); + wlen = 22; + break; + default: + errx(1, "internal error: silly AF"); + } + + cnt = atomicio(vwrite, proxyfd, buf, wlen); + if (cnt != wlen) + err(1, "write failed (%zu/%zu)", cnt, wlen); + + cnt = atomicio(read, proxyfd, buf, 4); + if (cnt != 4) + err(1, "read failed (%zu/4)", cnt); + if (buf[1] != 0) + errx(1, "connection failed, SOCKS error %d", buf[1]); + switch (buf[3]) { + case SOCKS_IPV4: + cnt = atomicio(read, proxyfd, buf + 4, 6); + if (cnt != 6) + err(1, "read failed (%zu/6)", cnt); + break; + case SOCKS_IPV6: + cnt = atomicio(read, proxyfd, buf + 4, 18); + if (cnt != 18) + err(1, "read failed (%zu/18)", cnt); + break; + default: + errx(1, "connection failed, unsupported address type"); + } + } else if (socksv == 4) { + /* This will exit on lookup failure */ + decode_addrport(host, port, (struct sockaddr *)&addr, + sizeof(addr), 1, 0); + + /* Version 4 */ + buf[0] = SOCKS_V4; + buf[1] = SOCKS_CONNECT; /* connect */ + memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port); + memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); + buf[8] = 0; /* empty username */ + wlen = 9; + + cnt = atomicio(vwrite, proxyfd, buf, wlen); + if (cnt != wlen) + err(1, "write failed (%zu/%zu)", cnt, wlen); + + cnt = atomicio(read, proxyfd, buf, 8); + if (cnt != 8) + err(1, "read failed (%zu/8)", cnt); + if (buf[1] != 90) + errx(1, "connection failed, SOCKS error %d", buf[1]); + } else if (socksv == -1) { + /* HTTP proxy CONNECT */ + + /* Disallow bad chars in hostname */ + if (strcspn(host, "\r\n\t []:") != strlen(host)) + errx(1, "Invalid hostname"); + + /* Try to be sane about numeric IPv6 addresses */ + if (strchr(host, ':') != NULL) { + r = snprintf(buf, sizeof(buf), + "CONNECT [%s]:%d HTTP/1.0\r\n", + host, ntohs(serverport)); + } else { + r = snprintf(buf, sizeof(buf), + "CONNECT %s:%d HTTP/1.0\r\n", + host, ntohs(serverport)); + } + if (r == -1 || (size_t)r >= sizeof(buf)) + errx(1, "hostname too long"); + r = strlen(buf); + + cnt = atomicio(vwrite, proxyfd, buf, r); + if (cnt != (size_t)r) + err(1, "write failed (%zu/%d)", cnt, r); + + if (authretry > 1) { + char resp[1024]; + + proxypass = getproxypass(proxyuser, proxyhost); + r = snprintf(buf, sizeof(buf), "%s:%s", + proxyuser, proxypass); + if (r == -1 || (size_t)r >= sizeof(buf) || + b64_ntop(buf, strlen(buf), resp, + sizeof(resp)) == -1) + errx(1, "Proxy username/password too long"); + r = snprintf(buf, sizeof(buf), "Proxy-Authorization: " + "Basic %s\r\n", resp); + if (r == -1 || (size_t)r >= sizeof(buf)) + errx(1, "Proxy auth response too long"); + r = strlen(buf); + if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != (size_t)r) + err(1, "write failed (%zu/%d)", cnt, r); + } + + /* Terminate headers */ + if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2) + err(1, "write failed (2/%d)", r); + + /* Read status reply */ + proxy_read_line(proxyfd, buf, sizeof(buf)); + if (proxyuser != NULL && + strncmp(buf, "HTTP/1.0 407 ", 12) == 0) { + if (authretry > 1) { + fprintf(stderr, "Proxy authentication " + "failed\n"); + } + close(proxyfd); + goto again; + } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0 && + strncmp(buf, "HTTP/1.1 200 ", 12) != 0) + errx(1, "Proxy error: \"%s\"", buf); + + /* Headers continue until we hit an empty line */ + for (r = 0; r < HTTP_MAXHDRS; r++) { + proxy_read_line(proxyfd, buf, sizeof(buf)); + if (*buf == '\0') + break; + } + if (*buf != '\0') + errx(1, "Too many proxy headers received"); + } else + errx(1, "Unknown proxy protocol %d", socksv); + + return (proxyfd); +} + -- cgit v1.2.3 From 27ca1a5c0095eda151934bca39a77e391f875d17 Mon Sep 17 00:00:00 2001 From: "markus@openbsd.org" Date: Mon, 12 Jan 2015 20:13:27 +0000 Subject: upstream commit unbreak parsing of pubkey comments; with gerhard; ok djm/deraadt --- regress/Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index ac1ee2d5f..dd3b79506 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,6 +1,6 @@ -# $OpenBSD: Makefile,v 1.72 2014/12/22 08:06:03 djm Exp $ +# $OpenBSD: Makefile,v 1.73 2015/01/12 20:13:27 markus Exp $ -REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t-exec +REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) # Interop tests are not run by default @@ -76,6 +76,7 @@ INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers USER!= id -un CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ t8.out t8.out.pub t9.out t9.out.pub t10.out t10.out.pub \ + t12.out t12.out.pub \ authorized_keys_${USER} known_hosts pidfile testdata \ ssh_config sshd_config.orig ssh_proxy sshd_config sshd_proxy \ rsa.pub rsa rsa1.pub rsa1 host.rsa host.rsa1 \ @@ -169,6 +170,12 @@ t11: ${TEST_SSH_SSHKEYGEN} -E sha256 -lf ${.CURDIR}/rsa_openssh.pub |\ awk '{print $$2}' | diff - ${.CURDIR}/t11.ok +t12.out: + ssh-keygen -q -t ed25519 -N '' -C 'test-comment-1234' -f $@ + +t12: t12.out + ssh-keygen -lf t12.out.pub | grep -q test-comment-1234 + t-exec: ${LTESTS:=.sh} @if [ "x$?" = "x" ]; then exit 0; fi; \ for TEST in ""$?; do \ -- cgit v1.2.3 From 0920553d0aee117a596b03ed5b49b280d34a32c5 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 13 Jan 2015 07:49:49 +0000 Subject: upstream commit regress test for PubkeyAcceptedKeyTypes; ok markus@ --- regress/Makefile | 7 +++-- regress/limit-keytype.sh | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 regress/limit-keytype.sh (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index dd3b79506..2e068e94a 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.73 2015/01/12 20:13:27 markus Exp $ +# $OpenBSD: Makefile,v 1.74 2015/01/13 07:49:49 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) @@ -65,7 +65,10 @@ LTESTS= connect \ forward-control \ integrity \ krl \ - multipubkey + multipubkey \ + limit-keytype + + # dhgex \ INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers diff --git a/regress/limit-keytype.sh b/regress/limit-keytype.sh new file mode 100644 index 000000000..2de037bd1 --- /dev/null +++ b/regress/limit-keytype.sh @@ -0,0 +1,80 @@ +# $OpenBSD: limit-keytype.sh,v 1.1 2015/01/13 07:49:49 djm Exp $ +# Placed in the Public Domain. + +tid="restrict pubkey type" + +rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/user_key* +rm -f $OBJ/authorized_principals_$USER $OBJ/cert_user_key* + +mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig +mv $OBJ/ssh_proxy $OBJ/ssh_proxy.orig + +# Create a CA key +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_ca_key ||\ + fatal "ssh-keygen failed" + +# Make some keys and a certificate. +${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_key1 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t rsa -f $OBJ/user_key2 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -N '' -t rsa -f $OBJ/user_key3 || \ + fatal "ssh-keygen failed" +${SSHKEYGEN} -q -s $OBJ/user_ca_key -I "regress user key for $USER" \ + -z $$ -n ${USER},mekmitasdigoat $OBJ/user_key3 || + fatal "couldn't sign user_key1" +# Copy the private key alongside the cert to allow better control of when +# it is offered. +mv $OBJ/user_key3-cert.pub $OBJ/cert_user_key3.pub +cp -p $OBJ/user_key3 $OBJ/cert_user_key3 + +grep -v IdentityFile $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy + +opts="-oProtocol=2 -F $OBJ/ssh_proxy -oIdentitiesOnly=yes" +fullopts="$opts -i $OBJ/cert_user_key3 -i $OBJ/user_key1 -i $OBJ/user_key2" + +echo mekmitasdigoat > $OBJ/authorized_principals_$USER +cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER +cat $OBJ/user_key2.pub >> $OBJ/authorized_keys_$USER + +prepare_config() { + ( + grep -v "Protocol" $OBJ/sshd_proxy.orig + echo "Protocol 2" + echo "AuthenticationMethods publickey" + echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" + echo "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" + for x in "$@" ; do + echo "$x" + done + ) > $OBJ/sshd_proxy +} + +prepare_config + +# Check we can log in with all key types. +${SSH} $opts -i $OBJ/cert_user_key3 proxy true || fatal "cert failed" +${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed" +${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed" + +# Allow plain Ed25519 and RSA. The certificate should fail. +verbose "privsep=$privsep allow rsa,ed25519" +prepare_config "PubkeyAcceptedKeyTypes ssh-rsa,ssh-ed25519" +${SSH} $opts -i $OBJ/cert_user_key3 proxy true && fatal "cert succeeded" +${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed" +${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed" + +# Allow Ed25519 only. +verbose "privsep=$privsep allow ed25519" +prepare_config "PubkeyAcceptedKeyTypes ssh-ed25519" +${SSH} $opts -i $OBJ/cert_user_key3 proxy true && fatal "cert succeeded" +${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed" +${SSH} $opts -i $OBJ/user_key2 proxy true && fatal "key2 succeeded" + +# Allow all certs. Plain keys should fail. +verbose "privsep=$privsep allow cert only" +prepare_config "PubkeyAcceptedKeyTypes ssh-*-cert-v01@openssh.com" +${SSH} $opts -i $OBJ/cert_user_key3 proxy true || fatal "cert failed" +${SSH} $opts -i $OBJ/user_key1 proxy true && fatal "key1 succeeded" +${SSH} $opts -i $OBJ/user_key2 proxy true && fatal "key2 succeeded" + -- cgit v1.2.3 From 771bb47a1df8b69061f09462e78aa0b66cd594bf Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 13 Jan 2015 14:51:51 +0000 Subject: upstream commit implement a SIGINFO handler so we can discern a stuck fuzz test from a merely glacial one; prompted by and ok markus --- regress/Makefile | 2 +- regress/unittests/test_helper/fuzz.c | 83 ++++++++++++++++++++++------- regress/unittests/test_helper/test_helper.c | 26 ++++++++- regress/unittests/test_helper/test_helper.h | 3 +- 4 files changed, 92 insertions(+), 22 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 2e068e94a..3d32857c6 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -96,7 +96,7 @@ CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ regress.log failed-regress.log ssh-log-wrapper.sh \ sftp-server.sh sftp-server.log sftp.log setuid-allowed \ data ed25519-agent ed25519-agent.pub key.ed25519-512 \ - key.ed25519-512.pub netcat + key.ed25519-512.pub netcat host_krl_* host_revoked_* user_*key* SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} diff --git a/regress/unittests/test_helper/fuzz.c b/regress/unittests/test_helper/fuzz.c index d8e1b7ec0..963bce3dc 100644 --- a/regress/unittests/test_helper/fuzz.c +++ b/regress/unittests/test_helper/fuzz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fuzz.c,v 1.4 2014/11/19 13:35:37 krw Exp $ */ +/* $OpenBSD: fuzz.c,v 1.5 2015/01/13 14:51:51 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -20,6 +20,7 @@ #include "includes.h" #include +#include #include #include @@ -29,8 +30,11 @@ #endif #include #include +#include +#include #include "test_helper.h" +#include "atomicio.h" /* #define FUZZ_DEBUG */ @@ -95,59 +99,73 @@ fuzz_ntop(u_int n) } } -void -fuzz_dump(struct fuzz *fuzz) +static int +fuzz_fmt(struct fuzz *fuzz, char *s, size_t n) { - u_char *p = fuzz_ptr(fuzz); - size_t i, j, len = fuzz_len(fuzz); + if (fuzz == NULL) + return -1; switch (fuzz->strategy) { case FUZZ_1_BIT_FLIP: - fprintf(stderr, "%s case %zu of %zu (bit: %zu)\n", + snprintf(s, n, "%s case %zu of %zu (bit: %zu)\n", fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->slen * 8, fuzz->o1); - break; + return 0; case FUZZ_2_BIT_FLIP: - fprintf(stderr, "%s case %llu of %llu (bits: %zu, %zu)\n", + snprintf(s, n, "%s case %llu of %llu (bits: %zu, %zu)\n", fuzz_ntop(fuzz->strategy), (((fuzz_ullong)fuzz->o2) * fuzz->slen * 8) + fuzz->o1, ((fuzz_ullong)fuzz->slen * 8) * fuzz->slen * 8, fuzz->o1, fuzz->o2); - break; + return 0; case FUZZ_1_BYTE_FLIP: - fprintf(stderr, "%s case %zu of %zu (byte: %zu)\n", + snprintf(s, n, "%s case %zu of %zu (byte: %zu)\n", fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->slen, fuzz->o1); - break; + return 0; case FUZZ_2_BYTE_FLIP: - fprintf(stderr, "%s case %llu of %llu (bytes: %zu, %zu)\n", + snprintf(s, n, "%s case %llu of %llu (bytes: %zu, %zu)\n", fuzz_ntop(fuzz->strategy), (((fuzz_ullong)fuzz->o2) * fuzz->slen) + fuzz->o1, ((fuzz_ullong)fuzz->slen) * fuzz->slen, fuzz->o1, fuzz->o2); - break; + return 0; case FUZZ_TRUNCATE_START: - fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n", + snprintf(s, n, "%s case %zu of %zu (offset: %zu)\n", fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->slen, fuzz->o1); - break; + return 0; case FUZZ_TRUNCATE_END: - fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n", + snprintf(s, n, "%s case %zu of %zu (offset: %zu)\n", fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->slen, fuzz->o1); - break; + return 0; case FUZZ_BASE64: assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1); - fprintf(stderr, "%s case %llu of %llu (offset: %zu char: %c)\n", + snprintf(s, n, "%s case %llu of %llu (offset: %zu char: %c)\n", fuzz_ntop(fuzz->strategy), (fuzz->o1 * (fuzz_ullong)64) + fuzz->o2, fuzz->slen * (fuzz_ullong)64, fuzz->o1, fuzz_b64chars[fuzz->o2]); - break; + return 0; default: + return -1; abort(); } +} + +void +fuzz_dump(struct fuzz *fuzz) +{ + u_char *p = fuzz_ptr(fuzz); + size_t i, j, len = fuzz_len(fuzz); + char buf[256]; + if (fuzz_fmt(fuzz, buf, sizeof(buf)) != 0) { + fprintf(stderr, "%s: fuzz invalid\n", __func__); + abort(); + } + fputs(buf, stderr); fprintf(stderr, "fuzz context %p len = %zu\n", fuzz, len); for (i = 0; i < len; i += 16) { fprintf(stderr, "%.4zd: ", i); @@ -170,6 +188,23 @@ fuzz_dump(struct fuzz *fuzz) } } +#ifdef SIGINFO +static struct fuzz *last_fuzz; + +static void +siginfo(int unused __unused) +{ + char buf[256]; + + test_info(buf, sizeof(buf)); + atomicio(vwrite, STDERR_FILENO, buf, strlen(buf)); + if (last_fuzz != NULL) { + fuzz_fmt(last_fuzz, buf, sizeof(buf)); + atomicio(vwrite, STDERR_FILENO, buf, strlen(buf)); + } +} +#endif + struct fuzz * fuzz_begin(u_int strategies, const void *p, size_t l) { @@ -189,6 +224,12 @@ fuzz_begin(u_int strategies, const void *p, size_t l) FUZZ_DBG(("begin, ret = %p", ret)); fuzz_next(ret); + +#ifdef SIGINFO + last_fuzz = ret; + signal(SIGINFO, siginfo); +#endif + return ret; } @@ -196,6 +237,10 @@ void fuzz_cleanup(struct fuzz *fuzz) { FUZZ_DBG(("cleanup, fuzz = %p", fuzz)); +#ifdef SIGINFO + last_fuzz = NULL; + signal(SIGINFO, SIG_DFL); +#endif assert(fuzz != NULL); assert(fuzz->seed != NULL); assert(fuzz->fuzzed != NULL); diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index d0bc67833..6f7f381c7 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.c,v 1.2 2014/05/02 09:41:32 andre Exp $ */ +/* $OpenBSD: test_helper.c,v 1.3 2015/01/13 14:51:51 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include @@ -39,6 +41,7 @@ #endif #include "test_helper.h" +#include "atomicio.h" #define TEST_CHECK_INT(r, pred) do { \ switch (pred) { \ @@ -179,6 +182,24 @@ test_data_file(const char *name) return ret; } +void +test_info(char *s, size_t len) +{ + snprintf(s, len, "In test %u - \"%s\"\n", test_number, + active_test_name == NULL ? "" : active_test_name); +} + +#ifdef SIGINFO +static void +siginfo(int unused __unused) +{ + char buf[256]; + + test_info(buf, sizeof(buf)); + atomicio(vwrite, STDERR_FILENO, buf, strlen(buf)); +} +#endif + void test_start(const char *n) { @@ -187,6 +208,9 @@ test_start(const char *n) if (verbose_mode) printf("test %u - \"%s\": ", test_number, active_test_name); test_number++; +#ifdef SIGINFO + signal(SIGINFO, siginfo); +#endif } void diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h index a398c615f..b6a39ea3e 100644 --- a/regress/unittests/test_helper/test_helper.h +++ b/regress/unittests/test_helper/test_helper.h @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.h,v 1.3 2014/05/02 09:41:32 andre Exp $ */ +/* $OpenBSD: test_helper.h,v 1.4 2015/01/13 14:51:51 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -40,6 +40,7 @@ void tests(void); const char *test_data_file(const char *name); void test_start(const char *n); +void test_info(char *s, size_t len); void set_onerror_func(test_onerror_func_t *f, void *ctx); void test_done(void); void ssl_err_check(const char *file, int line); -- cgit v1.2.3 From d59ec478c453a3fff05badbbfd96aa856364f2c2 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sun, 18 Jan 2015 19:47:55 +0000 Subject: upstream commit enable hostkey-agent.sh test --- regress/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 3d32857c6..23f1cbc9a 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.74 2015/01/13 07:49:49 djm Exp $ +# $OpenBSD: Makefile,v 1.75 2015/01/18 19:47:55 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) @@ -66,7 +66,8 @@ LTESTS= connect \ integrity \ krl \ multipubkey \ - limit-keytype + limit-keytype \ + hostkey-agent # dhgex \ -- cgit v1.2.3 From 7947810eab5fe0ad311f32a48f4d4eb1f71be6cf Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sun, 18 Jan 2015 22:00:18 +0000 Subject: upstream commit regression test for known_host file editing using ssh-keygen (-H / -R / -F) after hostkeys_foreach() change; feedback and ok markus@ --- regress/Makefile | 8 +- regress/keygen-knownhosts.sh | 197 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 regress/keygen-knownhosts.sh (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 23f1cbc9a..1c02aa819 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.75 2015/01/18 19:47:55 djm Exp $ +# $OpenBSD: Makefile,v 1.76 2015/01/18 22:00:18 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) @@ -67,7 +67,8 @@ LTESTS= connect \ krl \ multipubkey \ limit-keytype \ - hostkey-agent + hostkey-agent \ + keygen-knownhosts # dhgex \ @@ -97,7 +98,8 @@ CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ regress.log failed-regress.log ssh-log-wrapper.sh \ sftp-server.sh sftp-server.log sftp.log setuid-allowed \ data ed25519-agent ed25519-agent.pub key.ed25519-512 \ - key.ed25519-512.pub netcat host_krl_* host_revoked_* user_*key* + key.ed25519-512.pub netcat host_krl_* host_revoked_* \ + kh.* user_*key* SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} diff --git a/regress/keygen-knownhosts.sh b/regress/keygen-knownhosts.sh new file mode 100644 index 000000000..35a5ea499 --- /dev/null +++ b/regress/keygen-knownhosts.sh @@ -0,0 +1,197 @@ +# $OpenBSD: keygen-knownhosts.sh,v 1.1 2015/01/18 22:00:18 djm Exp $ +# Placed in the Public Domain. + +tid="ssh-keygen known_hosts" + +rm -f $OBJ/kh.* + +# Generate some keys for testing (just ed25519 for speed) and make a hosts file. +for x in host-a host-b host-c host-d host-e host-f host-a2 host-b2; do + ${SSHKEYGEN} -qt ed25519 -f $OBJ/kh.$x -C "$x" -N "" || \ + fatal "ssh-keygen failed" + # Add a comment that we expect should be preserved. + echo "# $x" >> $OBJ/kh.hosts + ( + case "$x" in + host-a|host-b) echo -n "$x " ;; + host-c) echo -n "@cert-authority $x " ;; + host-d) echo -n "@revoked $x " ;; + host-e) echo -n "host-e* " ;; + host-f) echo -n "host-f,host-g,host-h " ;; + host-a2) echo -n "host-a " ;; + host-b2) echo -n "host-b " ;; + esac + cat $OBJ/kh.${x}.pub + # Blank line should be preserved. + echo "" >> $OBJ/kh.hosts + ) >> $OBJ/kh.hosts +done + +# Generate a variant with an invalid line. We'll use this for most tests, +# because keygen should be able to cope and it should be preserved in any +# output file. +cat $OBJ/kh.hosts >> $OBJ/kh.invalid +echo "host-i " >> $OBJ/kh.invalid + +cp $OBJ/kh.invalid $OBJ/kh.invalid.orig +cp $OBJ/kh.hosts $OBJ/kh.hosts.orig + +expect_key() { + _host=$1 + _hosts=$2 + _key=$3 + _line=$4 + _mark=$5 + _marker="" + test "x$_mark" = "xCA" && _marker="@cert-authority " + test "x$_mark" = "xREVOKED" && _marker="@revoked " + test "x$_line" != "x" && + echo "# Host $_host found: line $_line $_mark" >> $OBJ/kh.expect + echo -n "${_marker}$_hosts " >> $OBJ/kh.expect + cat $OBJ/kh.${_key}.pub >> $OBJ/kh.expect || + fatal "${_key}.pub missing" +} + +check_find() { + _host=$1 + _name=$2 + _keygenopt=$3 + ${SSHKEYGEN} $_keygenopt -f $OBJ/kh.invalid -F $_host > $OBJ/kh.result + if ! diff -uw $OBJ/kh.expect $OBJ/kh.result ; then + fail "didn't find $_name" + fi +} + +# Find key +rm -f $OBJ/kh.expect +expect_key host-a host-a host-a 2 +expect_key host-a host-a host-a2 20 +check_find host-a "simple find" + +# find CA key +rm -f $OBJ/kh.expect +expect_key host-c host-c host-c 8 CA +check_find host-c "find CA key" + +# find revoked key +rm -f $OBJ/kh.expect +expect_key host-d host-d host-d 11 REVOKED +check_find host-d "find revoked key" + +# find key with wildcard +rm -f $OBJ/kh.expect +expect_key host-e.somedomain "host-e*" host-e 14 +check_find host-e.somedomain "find wildcard key" + +# find key among multiple hosts +rm -f $OBJ/kh.expect +expect_key host-h "host-f,host-g,host-h " host-f 17 +check_find host-h "find multiple hosts" + +check_hashed_find() { + _host=$1 + _name=$2 + _file=$3 + test "x$_file" = "x" && _file=$OBJ/kh.invalid + ${SSHKEYGEN} -f $_file -HF $_host | grep '|1|' | \ + sed "s/^[^ ]*/$_host/" > $OBJ/kh.result + if ! diff -uw $OBJ/kh.expect $OBJ/kh.result ; then + fail "didn't find $_name" + fi +} + +# Find key and hash +rm -f $OBJ/kh.expect +expect_key host-a host-a host-a +expect_key host-a host-a host-a2 +check_hashed_find host-a "find simple and hash" + +# Find CA key and hash +rm -f $OBJ/kh.expect +expect_key host-c host-c host-c "" CA +# CA key output is not hashed. +check_find host-c "find simple and hash" -H + +# Find revoked key and hash +rm -f $OBJ/kh.expect +expect_key host-d host-d host-d "" REVOKED +# Revoked key output is not hashed. +check_find host-d "find simple and hash" -H + +# find key with wildcard and hash +rm -f $OBJ/kh.expect +expect_key host-e "host-e*" host-e "" +# Key with wildcard hostname should not be hashed. +check_find host-e "find wildcard key" -H + +# find key among multiple hosts +rm -f $OBJ/kh.expect +# Comma-separated hostnames should be expanded and hashed. +expect_key host-f "host-h " host-f +expect_key host-g "host-h " host-f +expect_key host-h "host-h " host-f +check_hashed_find host-h "find multiple hosts" + +# Attempt remove key on invalid file. +cp $OBJ/kh.invalid.orig $OBJ/kh.invalid +${SSHKEYGEN} -qf $OBJ/kh.invalid -R host-a 2>/dev/null +diff -u $OBJ/kh.invalid $OBJ/kh.invalid.orig || fail "remove on invalid succeeded" + +# Remove key +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -R host-a 2>/dev/null +grep -v "^host-a " $OBJ/kh.hosts.orig > $OBJ/kh.expect +diff -u $OBJ/kh.hosts $OBJ/kh.expect || fail "remove simple" + +# Remove CA key +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -R host-c 2>/dev/null +# CA key should not be removed. +diff -u $OBJ/kh.hosts $OBJ/kh.hosts.orig || fail "remove CA" + +# Remove revoked key +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -R host-d 2>/dev/null +# revoked key should not be removed. +diff -u $OBJ/kh.hosts $OBJ/kh.hosts.orig || fail "remove revoked" + +# Remove wildcard +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -R host-e.blahblah 2>/dev/null +grep -v "^host-e[*] " $OBJ/kh.hosts.orig > $OBJ/kh.expect +diff -u $OBJ/kh.hosts $OBJ/kh.expect || fail "remove wildcard" + +# Remove multiple +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -R host-h 2>/dev/null +grep -v "^host-f," $OBJ/kh.hosts.orig > $OBJ/kh.expect +diff -u $OBJ/kh.hosts $OBJ/kh.expect || fail "remove wildcard" + +# Attempt hash on invalid file +cp $OBJ/kh.invalid.orig $OBJ/kh.invalid +${SSHKEYGEN} -qf $OBJ/kh.invalid -H 2>/dev/null && fail "hash invalid succeeded" +diff -u $OBJ/kh.invalid $OBJ/kh.invalid.orig || fail "invalid file modified" + +# Hash valid file +cp $OBJ/kh.hosts.orig $OBJ/kh.hosts +${SSHKEYGEN} -qf $OBJ/kh.hosts -H 2>/dev/null || fail "hash failed" +diff -u $OBJ/kh.hosts.old $OBJ/kh.hosts.orig || fail "backup differs" +grep "^host-[abfgh]" $OBJ/kh.hosts && fail "original hostnames persist" + +cp $OBJ/kh.hosts $OBJ/kh.hashed.orig + +# Test lookup +rm -f $OBJ/kh.expect +expect_key host-a host-a host-a +expect_key host-a host-a host-a2 +check_hashed_find host-a "find simple in hashed" $OBJ/kh.hosts + +# Test multiple expanded +rm -f $OBJ/kh.expect +expect_key host-h host-h host-f +check_hashed_find host-h "find simple in hashed" $OBJ/kh.hosts + +# Test remove +cp $OBJ/kh.hashed.orig $OBJ/kh.hashed +${SSHKEYGEN} -qf $OBJ/kh.hashed -R host-a 2>/dev/null +${SSHKEYGEN} -qf $OBJ/kh.hashed -F host-a && fail "found key after hashed remove" -- cgit v1.2.3 From 2b3b1c1e4bd9577b6e780c255c278542ea66c098 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 20 Jan 2015 22:58:57 +0000 Subject: upstream commit use SUBDIR to recuse into unit tests; makes "make obj" actually work --- regress/Makefile | 4 +++- regress/unittests/test_helper/Makefile | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 1c02aa819..c920661ae 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.76 2015/01/18 22:00:18 djm Exp $ +# $OpenBSD: Makefile,v 1.77 2015/01/20 22:58:57 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) @@ -205,4 +205,6 @@ unit: ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ ${.OBJDIR}/unittests/sshkey/test_sshkey \ -d ${.CURDIR}//unittests/sshkey/testdata ; \ + ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ + ${.OBJDIR}/unittests/kex/test_kex ; \ fi diff --git a/regress/unittests/test_helper/Makefile b/regress/unittests/test_helper/Makefile index 3e90903ef..5b3894cbf 100644 --- a/regress/unittests/test_helper/Makefile +++ b/regress/unittests/test_helper/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.1 2014/04/30 05:32:00 djm Exp $ +# $OpenBSD: Makefile,v 1.2 2015/01/20 22:58:57 djm Exp $ LIB= test_helper SRCS= test_helper.c fuzz.c @@ -7,6 +7,9 @@ DEBUGLIBS= no NOPROFILE= yes NOPIC= yes +# Hack to allow building with SUBDIR in ../../Makefile +regress: all + install: @echo -n -- cgit v1.2.3 From d411d395556b73ba1b9e451516a0bd6697c4b03d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 26 Jan 2015 06:12:18 +0000 Subject: upstream commit regression test for host key rotation --- regress/Makefile | 5 +- regress/hostkey-rotate.sh | 129 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 regress/hostkey-rotate.sh (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index c920661ae..58bcb38b6 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.77 2015/01/20 22:58:57 djm Exp $ +# $OpenBSD: Makefile,v 1.78 2015/01/26 06:12:18 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec tests: $(REGRESS_TARGETS) @@ -68,7 +68,8 @@ LTESTS= connect \ multipubkey \ limit-keytype \ hostkey-agent \ - keygen-knownhosts + keygen-knownhosts \ + hostkey-rotate # dhgex \ diff --git a/regress/hostkey-rotate.sh b/regress/hostkey-rotate.sh new file mode 100644 index 000000000..d964b35c2 --- /dev/null +++ b/regress/hostkey-rotate.sh @@ -0,0 +1,129 @@ +# $OpenBSD: hostkey-rotate.sh,v 1.1 2015/01/26 06:12:18 djm Exp $ +# Placed in the Public Domain. + +tid="hostkey rotate" + +# Need full names here since they are used in HostKeyAlgorithms +HOSTKEY_TYPES="ecdsa-sha2-nistp256 ssh-ed25519 ssh-rsa ssh-dss" + +rm -f $OBJ/hkr.* $OBJ/ssh_proxy.orig + +grep -vi 'hostkey' $OBJ/sshd_proxy > $OBJ/sshd_proxy.orig +echo "UpdateHostkeys=yes" >> $OBJ/ssh_proxy +rm $OBJ/known_hosts + +trace "prepare hostkeys" +nkeys=0 +all_algs="" +for k in `ssh -Q key-plain` ; do + ${SSHKEYGEN} -qt $k -f $OBJ/hkr.$k -N '' || fatal "ssh-keygen $k" + echo "Hostkey $OBJ/hkr.${k}" >> $OBJ/sshd_proxy.orig + nkeys=`expr $nkeys + 1` + test "x$all_algs" = "x" || all_algs="${all_algs}," + all_algs="${all_algs}$k" +done + +dossh() { + # All ssh should succeed in this test + ${SSH} -F $OBJ/ssh_proxy "$@" x true || fail "ssh $@ failed" +} + +expect_nkeys() { + _expected=$1 + _message=$2 + _n=`wc -l $OBJ/known_hosts | awk '{ print $1 }'` || fatal "wc failed" + [ "x$_n" = "x$_expected" ] || fail "$_message (got $_n wanted $_expected)" +} + +check_key_present() { + _type=$1 + _kfile=$2 + _prog='print $2 " " $3' + test "x$_kfile" = "x" && _kfile="$OBJ/hkr.${_type}.pub" + _ktext=`awk "/ $_type / { $_prog }" < $OBJ/known_hosts` || \ + fatal "awk failed" + grep -q "$_ktext" $_kfile +} + +cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy + +# Connect to sshd with StrictHostkeyChecking=no +verbose "learn hostkey with StrictHostKeyChecking=no" +>$OBJ/known_hosts +dossh -oHostKeyAlgorithms=ssh-ed25519 -oStrictHostKeyChecking=no +# Verify no additional keys learned +expect_nkeys 1 "unstrict connect keys" +check_key_present ssh-ed25519 || fail "unstrict didn't learn key" + +# Connect to sshd as usual +verbose "learn additional hostkeys" +dossh -oStrictHostKeyChecking=yes +# Check that other keys learned +expect_nkeys $nkeys "learn hostkeys" +check_key_present ssh-rsa || fail "didn't learn keys" + +# Check each key type +for k in `ssh -Q key-plain` ; do + verbose "learn additional hostkeys, type=$k" + dossh -oStrictHostKeyChecking=yes -oHostKeyAlgorithms=$k,$all_algs + expect_nkeys $nkeys "learn hostkeys $k" + check_key_present $k || fail "didn't learn $k" +done + +# Change one hostkey (non primary) and relearn +verbose "learn changed non-primary hostkey" +mv $OBJ/hkr.ssh-rsa.pub $OBJ/hkr.ssh-rsa.pub.old +rm -f $OBJ/hkr.ssh-rsa +${SSHKEYGEN} -qt ssh-rsa -f $OBJ/hkr.ssh-rsa -N '' || fatal "ssh-keygen $k" +dossh -oStrictHostKeyChecking=yes +# Check that the key was replaced +expect_nkeys $nkeys "learn hostkeys" +check_key_present ssh-rsa $OBJ/hkr.ssh-rsa.pub.old && fail "old key present" +check_key_present ssh-rsa || fail "didn't learn changed key" + +# Add new hostkey (primary type) to sshd and connect +verbose "learn new primary hostkey" +${SSHKEYGEN} -qt ssh-rsa -f $OBJ/hkr.ssh-rsa-new -N '' || fatal "ssh-keygen $k" +( cat $OBJ/sshd_proxy.orig ; echo HostKey $OBJ/hkr.ssh-rsa-new ) \ + > $OBJ/sshd_proxy +# Check new hostkey added +dossh -oStrictHostKeyChecking=yes -oHostKeyAlgorithms=ssh-rsa,$all_algs +expect_nkeys `expr $nkeys + 1` "learn hostkeys" +check_key_present ssh-rsa || fail "current key missing" +check_key_present ssh-rsa $OBJ/hkr.ssh-rsa-new.pub || fail "new key missing" + +# Remove old hostkey (primary type) from sshd +verbose "rotate primary hostkey" +cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy +mv $OBJ/hkr.ssh-rsa.pub $OBJ/hkr.ssh-rsa.pub.old +mv $OBJ/hkr.ssh-rsa-new.pub $OBJ/hkr.ssh-rsa.pub +mv $OBJ/hkr.ssh-rsa-new $OBJ/hkr.ssh-rsa +# Check old hostkey removed +dossh -oStrictHostKeyChecking=yes -oHostKeyAlgorithms=ssh-rsa,$all_algs +expect_nkeys $nkeys "learn hostkeys" +check_key_present ssh-rsa $OBJ/hkr.ssh-rsa.pub.old && fail "old key present" +check_key_present ssh-rsa || fail "didn't learn changed key" + +# Connect again, forcing rotated key +verbose "check rotate primary hostkey" +dossh -oStrictHostKeyChecking=yes -oHostKeyAlgorithms=ssh-rsa +expect_nkeys 1 "learn hostkeys" +check_key_present ssh-rsa || fail "didn't learn changed key" + +# $OpenBSD: hostkey-rotate.sh,v 1.1 2015/01/26 06:12:18 djm Exp $ +# Placed in the Public Domain. + +tid="hostkey rotate" + +# Prepare hostkeys file with one key + +# Connect to sshd + +# Check that other keys learned + +# Change one hostkey (non primary) + +# Connect to sshd + +# Check that the key was replaced + -- cgit v1.2.3 From 358964f3082fb90b2ae15bcab07b6105cfad5a43 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 27 Jan 2015 23:07:25 +1100 Subject: use ssh-keygen under test rather than system's --- regress/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 58bcb38b6..b30a7133b 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -100,7 +100,7 @@ CLEANFILES= t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \ sftp-server.sh sftp-server.log sftp.log setuid-allowed \ data ed25519-agent ed25519-agent.pub key.ed25519-512 \ key.ed25519-512.pub netcat host_krl_* host_revoked_* \ - kh.* user_*key* + kh.* user_*key* agent-key.* known_hosts.* hkr.* SUDO_CLEAN+= /var/run/testdata_${USER} /var/run/keycommand_${USER} @@ -178,10 +178,10 @@ t11: awk '{print $$2}' | diff - ${.CURDIR}/t11.ok t12.out: - ssh-keygen -q -t ed25519 -N '' -C 'test-comment-1234' -f $@ + ${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -C 'test-comment-1234' -f $@ t12: t12.out - ssh-keygen -lf t12.out.pub | grep -q test-comment-1234 + ${TEST_SSH_SSHKEYGEN} -lf t12.out.pub | grep -q test-comment-1234 t-exec: ${LTESTS:=.sh} @if [ "x$?" = "x" ]; then exit 0; fi; \ -- cgit v1.2.3 From e89c780886b23600de1e1c8d74aabd1ff61f43f0 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 17 Feb 2015 10:04:55 +1100 Subject: hook up hostkeys unittest to portable Makefiles --- Makefile.in | 16 ++++++++++++++++ regress/Makefile | 4 +++- regress/unittests/hostkeys/test_iterate.c | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/Makefile.in b/Makefile.in index 5119d6a30..c8783156e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -236,6 +236,8 @@ clean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/hostkeys/*.o + rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o rm -f regress/unittests/kex/test_kex (cd openbsd-compat && $(MAKE) clean) @@ -254,6 +256,8 @@ distclean: regressclean rm -f regress/unittests/sshkey/test_sshkey rm -f regress/unittests/bitmap/*.o rm -f regress/unittests/bitmap/test_bitmap + rm -f regress/unittests/hostkeys/*.o + rm -f regress/unittests/hostkeys/test_hostkeys rm -f regress/unittests/kex/*.o rm -f regress/unittests/kex/test_kex (cd openbsd-compat && $(MAKE) distclean) @@ -509,6 +513,17 @@ regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \ regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +UNITTESTS_TEST_HOSTKEYS_OBJS=\ + regress/unittests/hostkeys/tests.o \ + regress/unittests/hostkeys/test_iterate.o + +regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \ + ${UNITTESTS_TEST_HOSTKEYS_OBJS} \ + regress/unittests/test_helper/libtest_helper.a libssh.a + $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_HOSTKEYS_OBJS) \ + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + REGRESS_BINARIES=\ regress/modpipe$(EXEEXT) \ regress/setuid-allowed$(EXEEXT) \ @@ -516,6 +531,7 @@ REGRESS_BINARIES=\ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) \ regress/unittests/bitmap/test_bitmap$(EXEEXT) \ + regress/unittests/hostkeys/test_hostkeys$(EXEEXT) \ regress/unittests/kex/test_kex$(EXEEXT) tests interop-tests t-exec: regress-prep $(TARGETS) $(REGRESS_BINARIES) diff --git a/regress/Makefile b/regress/Makefile index b30a7133b..a5eaa0997 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -205,7 +205,9 @@ unit: set -e ; if test -z "${SKIP_UNIT}" ; then \ ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ ${.OBJDIR}/unittests/sshkey/test_sshkey \ - -d ${.CURDIR}//unittests/sshkey/testdata ; \ + -d ${.CURDIR}/unittests/sshkey/testdata ; \ ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ ${.OBJDIR}/unittests/kex/test_kex ; \ + ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ + -d ${.CURDIR}/unittests/hostkeys/testdata ; \ fi diff --git a/regress/unittests/hostkeys/test_iterate.c b/regress/unittests/hostkeys/test_iterate.c index 92d3a8345..c681f19f3 100644 --- a/regress/unittests/hostkeys/test_iterate.c +++ b/regress/unittests/hostkeys/test_iterate.c @@ -12,7 +12,7 @@ #include #include -#include "test_helper.h" +#include "../test_helper/test_helper.h" #include "sshkey.h" #include "authfile.h" -- cgit v1.2.3 From f81f1bbc5b892c8614ea740b1f92735652eb43f0 Mon Sep 17 00:00:00 2001 From: Tim Rice Date: Sat, 21 Feb 2015 18:12:10 -0800 Subject: out of tree build fix --- regress/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index a5eaa0997..ecc688cab 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -178,10 +178,10 @@ t11: awk '{print $$2}' | diff - ${.CURDIR}/t11.ok t12.out: - ${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -C 'test-comment-1234' -f $@ + ${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -C 'test-comment-1234' -f $(OBJ)/$@ t12: t12.out - ${TEST_SSH_SSHKEYGEN} -lf t12.out.pub | grep -q test-comment-1234 + ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t12.out.pub | grep -q test-comment-1234 t-exec: ${LTESTS:=.sh} @if [ "x$?" = "x" ]; then exit 0; fi; \ -- cgit v1.2.3 From bd58853102cee739f0e115e6d4b5334332ab1442 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 25 Feb 2015 16:58:22 -0800 Subject: valgrind support --- regress/Makefile | 13 ++++++---- regress/integrity.sh | 2 +- regress/multiplex.sh | 2 +- regress/reconfigure.sh | 18 ++++++++------ regress/sshd-log-wrapper.sh | 8 +++--- regress/test-exec.sh | 59 +++++++++++++++++++++++++++++++++++++++++---- regress/valgrind-unit.sh | 20 +++++++++++++++ 7 files changed, 97 insertions(+), 25 deletions(-) create mode 100755 regress/valgrind-unit.sh (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index ecc688cab..7005b410d 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -203,11 +203,14 @@ interop: ${INTEROP_TARGETS} # Unit tests, built by top-level Makefile unit: set -e ; if test -z "${SKIP_UNIT}" ; then \ - ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ - ${.OBJDIR}/unittests/sshkey/test_sshkey \ + V="" ; \ + test "x${USE_VALGRIND}" != "x" && \ + V=${.CURDIR}/valgrind-unit.sh ; \ + $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ + $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -d ${.CURDIR}/unittests/sshkey/testdata ; \ - ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ - ${.OBJDIR}/unittests/kex/test_kex ; \ - ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ + $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ + $$V ${.OBJDIR}/unittests/kex/test_kex ; \ + $$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ -d ${.CURDIR}/unittests/hostkeys/testdata ; \ fi diff --git a/regress/integrity.sh b/regress/integrity.sh index 42cb46422..2ff8b3f17 100644 --- a/regress/integrity.sh +++ b/regress/integrity.sh @@ -20,7 +20,7 @@ echo "KexAlgorithms diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" \ >> $OBJ/ssh_proxy # sshd-command for proxy (see test-exec.sh) -cmd="$SUDO sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy" +cmd="$SUDO sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" for m in $macs; do trace "test $tid: mac $m" diff --git a/regress/multiplex.sh b/regress/multiplex.sh index 617615355..acb9234d9 100644 --- a/regress/multiplex.sh +++ b/regress/multiplex.sh @@ -90,7 +90,7 @@ $NC -N -Ul $OBJ/unix-1.fwd < ${DATA} > /dev/null & netcat_pid=$! ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -L$OBJ/unix-2.fwd:$OBJ/unix-1.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 ${SSH} -F $OBJ/ssh_config -S $CTL -Oforward -R$OBJ/unix-3.fwd:$OBJ/unix-2.fwd otherhost >>$TEST_SSH_LOGFILE 2>&1 -$NC -U $OBJ/unix-3.fwd < /dev/null > ${COPY} +$NC -U $OBJ/unix-3.fwd < /dev/null > ${COPY} 2>/dev/null cmp ${DATA} ${COPY} || fail "ssh: corrupted copy of ${DATA}" kill $netcat_pid 2>/dev/null rm -f ${COPY} $OBJ/unix-[123].fwd diff --git a/regress/reconfigure.sh b/regress/reconfigure.sh index 1a42c21b7..e6af9eab1 100644 --- a/regress/reconfigure.sh +++ b/regress/reconfigure.sh @@ -4,14 +4,16 @@ tid="simple connect after reconfigure" # we need the full path to sshd for -HUP -case $SSHD in -/*) - # full path is OK - ;; -*) - # otherwise make fully qualified - SSHD=$OBJ/$SSHD -esac +if test "x$USE_VALGRIND" = "x" ; then + case $SSHD in + /*) + # full path is OK + ;; + *) + # otherwise make fully qualified + SSHD=$OBJ/$SSHD + esac +fi start_sshd diff --git a/regress/sshd-log-wrapper.sh b/regress/sshd-log-wrapper.sh index a9386be4d..c00934c78 100644 --- a/regress/sshd-log-wrapper.sh +++ b/regress/sshd-log-wrapper.sh @@ -3,11 +3,9 @@ # Placed in the Public Domain. # # simple wrapper for sshd proxy mode to catch stderr output -# sh sshd-log-wrapper.sh /path/to/sshd /path/to/logfile +# sh sshd-log-wrapper.sh /path/to/logfile /path/to/sshd [args...] -sshd=$1 -log=$2 -shift +log=$1 shift -exec $sshd -E$log $@ +exec "$@" -E$log diff --git a/regress/test-exec.sh b/regress/test-exec.sh index a1bab832f..ff0768a04 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -141,6 +141,55 @@ case "$SSHAGENT" in *) SSHAGENT=`which $SSHAGENT` ;; esac +# Record the actual binaries used. +SSH_BIN=${SSH} +SSHD_BIN=${SSHD} +SSHAGENT_BIN=${SSHAGENT} +SSHADD_BIN=${SSHADD} +SSHKEYGEN_BIN=${SSHKEYGEN} +SSHKEYSCAN_BIN=${SSHKEYSCAN} +SFTP_BIN=${SFTP} +SFTPSERVER_BIN=${SFTPSERVER} +SCP_BIN=${SCP} + +if [ "x$USE_VALGRIND" != "x" ]; then + mkdir -p $OBJ/valgrind-out + VG_TEST=`basename $SCRIPT .sh` + + # Some tests are difficult to fix. + case "$VG_TEST" in + connect-privsep|reexec) + VG_SKIP=1 ;; + esac + + if [ x"$VG_SKIP" = "x" ]; then + VG_IGNORE="/bin/*,/sbin/*,/usr/*,/var/*" + VG_LOG="$OBJ/valgrind-out/${VG_TEST}." + VG_OPTS="--track-origins=yes --leak-check=full" + VG_OPTS="$VG_OPTS --trace-children=yes" + VG_OPTS="$VG_OPTS --trace-children-skip=${VG_IGNORE}" + VG_PATH="valgrind" + if [ "x$VALGRIND_PATH" != "x" ]; then + VG_PATH="$VALGRIND_PATH" + fi + VG="$VG_PATH $VG_OPTS" + SSH="$VG --log-file=${VG_LOG}ssh.%p $SSH" + SSHD="$VG --log-file=${VG_LOG}sshd.%p $SSHD" + SSHAGENT="$VG --log-file=${VG_LOG}ssh-agent.%p $SSHAGENT" + SSHADD="$VG --log-file=${VG_LOG}ssh-add.%p $SSHADD" + SSHKEYGEN="$VG --log-file=${VG_LOG}ssh-keygen.%p $SSHKEYGEN" + SSHKEYSCAN="$VG --log-file=${VG_LOG}ssh-keyscan.%p $SSHKEYSCAN" + SFTP="$VG --log-file=${VG_LOG}sftp.%p ${SFTP}" + SCP="$VG --log-file=${VG_LOG}scp.%p $SCP" + cat > $OBJ/valgrind-sftp-server.sh << EOF +#!/bin/sh +exec $VG --log-file=${VG_LOG}sftp-server.%p $SFTPSERVER "\$@" +EOF + chmod a+rx $OBJ/valgrind-sftp-server.sh + SFTPSERVER="$OBJ/valgrind-sftp-server.sh" + fi +fi + # Logfiles. # SSH_LOGFILE should be the debug output of ssh(1) only # SSHD_LOGFILE should be the debug output of sshd(8) only @@ -175,7 +224,7 @@ SSH="$SSHLOGWRAP" # [kbytes] to ensure the file is at least that large. DATANAME=data DATA=$OBJ/${DATANAME} -cat ${SSHAGENT} >${DATA} +cat ${SSHAGENT_BIN} >${DATA} chmod u+w ${DATA} COPY=$OBJ/copy rm -f ${COPY} @@ -183,7 +232,7 @@ rm -f ${COPY} increase_datafile_size() { while [ `du -k ${DATA} | cut -f1` -lt $1 ]; do - cat ${SSHAGENT} >>${DATA} + cat ${SSHAGENT_BIN} >>${DATA} done } @@ -388,7 +437,7 @@ rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER trace "generate keys" for t in rsa rsa1; do # generate user key - if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN} -nt $OBJ/$t ]; then + if [ ! -f $OBJ/$t ] || [ ${SSHKEYGEN_BIN} -nt $OBJ/$t ]; then rm -f $OBJ/$t ${SSHKEYGEN} -q -N '' -t $t -f $OBJ/$t ||\ fail "ssh-keygen for $t failed" @@ -451,7 +500,7 @@ if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then echo "Hostname=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy - echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy + echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy REGRESS_INTEROP_PUTTY=yes fi @@ -459,7 +508,7 @@ fi # create a proxy version of the client config ( cat $OBJ/ssh_config - echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSHD_LOGFILE} -i -f $OBJ/sshd_proxy + echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy ) > $OBJ/ssh_proxy # check proxy config diff --git a/regress/valgrind-unit.sh b/regress/valgrind-unit.sh new file mode 100755 index 000000000..433cb069a --- /dev/null +++ b/regress/valgrind-unit.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +UNIT_BINARY="$1" +shift +UNIT_ARGS="$@" + +test "x$OBJ" = "x" && OBJ=$PWD + +# This mostly replicates the logic in test-exec.sh for running the +# regress tests under valgrind. +VG_TEST=`basename $UNIT_BINARY` +VG_LOG="$OBJ/valgrind-out/${VG_TEST}.%p" +VG_OPTS="--track-origins=yes --leak-check=full --log-file=${VG_LOG}" +VG_OPTS="$VG_OPTS --trace-children=yes" +VG_PATH="valgrind" +if [ "x$VALGRIND_PATH" != "x" ]; then + VG_PATH="$VALGRIND_PATH" +fi + +exec $VG_PATH $VG_OPTS $UNIT_BINARY $UNIT_ARGS -- cgit v1.2.3 From 9e1cfca7e1fe9cf8edb634fc894e43993e4da1ea Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 26 Feb 2015 20:32:58 -0800 Subject: create OBJ/valgrind-out before running unittests --- regress/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 7005b410d..13e3fc8ab 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,11 +1,14 @@ # $OpenBSD: Makefile,v 1.78 2015/01/26 06:12:18 djm Exp $ REGRESS_TARGETS= unit t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t-exec -tests: $(REGRESS_TARGETS) +tests: prep $(REGRESS_TARGETS) # Interop tests are not run by default interop interop-tests: t-exec-interop +prep: + test "x${USE_VALGRIND}" != "x" && mkdir -p $(OBJ)/valgrind-out + clean: for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done test -z "${SUDO}" || ${SUDO} rm -f ${SUDO_CLEAN} -- cgit v1.2.3 From f7f3116abf2a6e2f309ab096b08c58d19613e5d0 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 27 Feb 2015 15:52:49 -0800 Subject: twiddle test for portability --- regress/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 13e3fc8ab..860c53f5a 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -207,7 +207,7 @@ interop: ${INTEROP_TARGETS} unit: set -e ; if test -z "${SKIP_UNIT}" ; then \ V="" ; \ - test "x${USE_VALGRIND}" != "x" && \ + test "x${USE_VALGRIND}" = "x" || \ V=${.CURDIR}/valgrind-unit.sh ; \ $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -- cgit v1.2.3 From 02973ad5f6f49d8420e50a392331432b0396c100 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sat, 28 Feb 2015 08:05:27 -0800 Subject: twiddle another test for portability from Tom G. Christensen --- regress/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 860c53f5a..1eef340a7 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -7,7 +7,7 @@ tests: prep $(REGRESS_TARGETS) interop interop-tests: t-exec-interop prep: - test "x${USE_VALGRIND}" != "x" && mkdir -p $(OBJ)/valgrind-out + test "x${USE_VALGRIND}" = "x" || mkdir -p $(OBJ)/valgrind-out clean: for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done -- cgit v1.2.3 From 9f82e5a9042f2d872e98f48a876fcab3e25dd9bb Mon Sep 17 00:00:00 2001 From: Tim Rice Date: Mon, 16 Mar 2015 22:49:20 -0700 Subject: portability fix: Solaris systems may not have a grep that understands -q --- regress/Makefile | 2 +- regress/test-exec.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'regress/Makefile') diff --git a/regress/Makefile b/regress/Makefile index 1eef340a7..99a7d60f5 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -184,7 +184,7 @@ t12.out: ${TEST_SSH_SSHKEYGEN} -q -t ed25519 -N '' -C 'test-comment-1234' -f $(OBJ)/$@ t12: t12.out - ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t12.out.pub | grep -q test-comment-1234 + ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t12.out.pub | grep test-comment-1234 >/dev/null t-exec: ${LTESTS:=.sh} @if [ "x$?" = "x" ]; then exit 0; fi; \ diff --git a/regress/test-exec.sh b/regress/test-exec.sh index 12ba094a9..0f766620d 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -381,7 +381,7 @@ fatal () ssh_version () { - echo ${SSH_PROTOCOLS} | grep -q "$1" + echo ${SSH_PROTOCOLS} | grep "$1" >/dev/null } RESULT=0 -- cgit v1.2.3