From 3a77587ed077d4a6f993d933960b2467e280e096 Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Thu, 13 Apr 2023 00:19:18 +0800 Subject: [PATCH 01/10] Add support for AF_UNIX --- contrib/win32/win32compat/socketio.c | 10 ++++++++-- contrib/win32/win32compat/w32fd.c | 16 +++++----------- session.c | 14 +++++++++++++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c index c4eceaea8f71..980e9d6ee566 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -118,7 +119,7 @@ socketio_acceptEx(struct w32_io* pio) } /* create accepting socket */ - context->accept_socket = socket(addr.ss_family, SOCK_STREAM, IPPROTO_TCP); + context->accept_socket = socket(addr.ss_family, SOCK_STREAM, IPPROTO_IP); if (context->accept_socket == INVALID_SOCKET) { errno = errno_from_WSALastError(); debug3("acceptEx - socket() ERROR:%d, io:%p", WSAGetLastError(), pio); @@ -756,7 +757,7 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) int socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) { - + struct sockaddr_un tmp_unix; struct sockaddr_in tmp_addr4; struct sockaddr_in6 tmp_addr6; SOCKADDR* tmp_addr; @@ -778,6 +779,11 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) tmp_addr4.sin_port = 0; tmp_addr = (SOCKADDR*)&tmp_addr4; tmp_addr_len = sizeof(tmp_addr4); + } else if (name->sa_family == AF_UNIX) { + ZeroMemory(&tmp_unix, sizeof(tmp_unix)); + tmp_unix.sun_family = AF_UNIX; + tmp_addr = (SOCKADDR*)&tmp_unix; + tmp_addr_len = sizeof(tmp_unix); } else { errno = ENOTSUP; debug3("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio); diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index ed9309d54d2f..7c57c7f0d297 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -299,17 +299,11 @@ w32_socket(int domain, int type, int protocol) if (min_index == -1) return -1; - if (domain == AF_UNIX && type == SOCK_STREAM) { - pio = fileio_afunix_socket(); - if (pio == NULL) - return -1; - pio->type = NONSOCK_FD; - } else { - pio = socketio_socket(domain, type, protocol); - if (pio == NULL) - return -1; - pio->type = SOCK_FD; - } + pio = socketio_socket(domain, type, protocol); + if (pio == NULL) + return -1; + pio->type = SOCK_FD; + fd_table_set(pio, min_index); debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); diff --git a/session.c b/session.c index cb613dbb4838..d148458c9ebf 100644 --- a/session.c +++ b/session.c @@ -198,8 +198,15 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) /* Temporarily drop privileged uid for mkdir/bind. */ temporarily_use_uid(pw); +#ifdef WINDOWS + /* Allocate a buffer for the socket name, and format the name. */ + auth_sock_dir = xstrdup("C:\\tmp\\ssh-XXXXXXXXXX"); + +#else /* Allocate a buffer for the socket name, and format the name. */ auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); +#endif + /* Create private directory for socket */ if (mkdtemp(auth_sock_dir) == NULL) { @@ -211,8 +218,13 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) goto authsock_err; } +#ifdef WINDOWS + xasprintf(&auth_sock_name, "%s\\agent.%ld", + auth_sock_dir, (long)getpid()); +#else xasprintf(&auth_sock_name, "%s/agent.%ld", - auth_sock_dir, (long) getpid()); + auth_sock_dir, (long)getpid()); +#endif /* Start a Unix listener on auth_sock_name. */ sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0); From f7a8825765cfe5fc5b44d63d16751076f78d2bd9 Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Thu, 13 Apr 2023 22:47:49 +0800 Subject: [PATCH 02/10] Guard AF_UNIX paths with HAVE_AFUNIX_H --- contrib/win32/openssh/config.h.vs | 3 +++ contrib/win32/win32compat/socketio.c | 12 ++++++++++++ contrib/win32/win32compat/w32fd.c | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index d19b10758627..e6b13a10294d 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1526,6 +1526,9 @@ /* Use PIPES instead of a socketpair() */ #define USE_PIPES 1 +/* define 1 if afunix.h is available */ +#define HAVE_AFUNIX_H 1 + /* Define if you want to sanitize fds */ /* #undef USE_SANITISE_STDFD */ diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c index 980e9d6ee566..589ff5d8a554 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -29,7 +29,9 @@ */ #include +#ifdef HAVE_AFUNIX_H #include +#endif #include #include #include @@ -119,7 +121,12 @@ socketio_acceptEx(struct w32_io* pio) } /* create accepting socket */ + #ifdef HAVE_AFUNIX_H context->accept_socket = socket(addr.ss_family, SOCK_STREAM, IPPROTO_IP); + #else + context->accept_socket = socket(addr.ss_family, SOCK_STREAM, IPPROTO_TCP); + #endif + if (context->accept_socket == INVALID_SOCKET) { errno = errno_from_WSALastError(); debug3("acceptEx - socket() ERROR:%d, io:%p", WSAGetLastError(), pio); @@ -757,7 +764,10 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) int socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) { + #ifdef HAVE_AFUNIX_H struct sockaddr_un tmp_unix; + #endif + struct sockaddr_in tmp_addr4; struct sockaddr_in6 tmp_addr6; SOCKADDR* tmp_addr; @@ -779,11 +789,13 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) tmp_addr4.sin_port = 0; tmp_addr = (SOCKADDR*)&tmp_addr4; tmp_addr_len = sizeof(tmp_addr4); + #ifdef HAVE_AFUNIX_H } else if (name->sa_family == AF_UNIX) { ZeroMemory(&tmp_unix, sizeof(tmp_unix)); tmp_unix.sun_family = AF_UNIX; tmp_addr = (SOCKADDR*)&tmp_unix; tmp_addr_len = sizeof(tmp_unix); + #endif } else { errno = ENOTSUP; debug3("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio); diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 7c57c7f0d297..ebcfeb8e7d6f 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -298,12 +298,25 @@ w32_socket(int domain, int type, int protocol) errno = 0; if (min_index == -1) return -1; - + + #ifdef HAVE_AFUNIX_H pio = socketio_socket(domain, type, protocol); if (pio == NULL) return -1; pio->type = SOCK_FD; - + #else + if (domain == AF_UNIX && type == SOCK_STREAM) { + pio = fileio_afunix_socket(); + if (pio == NULL) + return -1; + pio->type = NONSOCK_FD; + } else { + pio = socketio_socket(domain, type, protocol); + if (pio == NULL) + return -1; + pio->type = SOCK_FD; + } + #endif fd_table_set(pio, min_index); debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); From 6dd4311e2102c65eb0d4d0fe8cc0df3a2a50fbbd Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Fri, 14 Apr 2023 04:49:35 +0800 Subject: [PATCH 03/10] Use Windows GetTempPath instead of /tmp --- contrib/win32/win32compat/socketio.c | 7 ++++--- contrib/win32/win32compat/w32fd.c | 1 + session.c | 17 ++++++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c index 589ff5d8a554..d85f28ff6036 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -29,9 +29,6 @@ */ #include -#ifdef HAVE_AFUNIX_H -#include -#endif #include #include #include @@ -41,6 +38,10 @@ #include "inc\utf.h" #include "misc_internal.h" #include "debug.h" +#include "../../../config.h" +#ifdef HAVE_AFUNIX_H +#include +#endif #define INTERNAL_SEND_BUFFER_SIZE 70*1024 //70KB #define INTERNAL_RECV_BUFFER_SIZE 70*1024 //70KB diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index ebcfeb8e7d6f..d3c6fbe26c7e 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -52,6 +52,7 @@ #include #include "misc_internal.h" #include "debug.h" +#include "../../../config.h" /* internal table that stores the fd to w32_io mapping*/ struct w32fd_table { diff --git a/session.c b/session.c index d148458c9ebf..e8972fd4ba60 100644 --- a/session.c +++ b/session.c @@ -199,15 +199,26 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) temporarily_use_uid(pw); #ifdef WINDOWS - /* Allocate a buffer for the socket name, and format the name. */ - auth_sock_dir = xstrdup("C:\\tmp\\ssh-XXXXXXXXXX"); + /* Use Windows temporal directory instead of unix `/tmp` folder */ + static char tmp_file_path[MAX_PATH]; + DWORD tmp_path_len = GetTempPath(MAX_PATH, tmp_file_path); + if (tmp_path_len > MAX_PATH || tmp_file_path == 0) { + error("Agent forwarding disabled: GetTempPath() failed."); + return 0; + } + char* ssh_prefix = xstrdup("ssh-XXXXXXXXXX"); + size_t sock_dir_len = tmp_path_len + strlen(ssh_prefix) + 1; + + auth_sock_dir = xmalloc(sock_dir_len); + memset(auth_sock_dir, 0, sock_dir_len); + strcat(auth_sock_dir, tmp_file_path); + strcat(auth_sock_dir, ssh_prefix); #else /* Allocate a buffer for the socket name, and format the name. */ auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); #endif - /* Create private directory for socket */ if (mkdtemp(auth_sock_dir) == NULL) { ssh_packet_send_debug(ssh, "Agent forwarding disabled: " From b31d18151eb5368feabfde408bcdf5d732a6bc2e Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Sat, 15 Apr 2023 03:23:47 +0800 Subject: [PATCH 04/10] Conditionally use af_unix and fileio --- authfd.c | 8 ++- contrib/win32/openssh/config.h.vs | 3 + contrib/win32/win32compat/ssh-agent/agent.c | 2 - contrib/win32/win32compat/w32fd.c | 64 +++++++++++++++++++-- contrib/win32/win32compat/w32fd.h | 1 + misc.c | 4 ++ mux.c | 8 ++- 7 files changed, 80 insertions(+), 10 deletions(-) diff --git a/authfd.c b/authfd.c index b633e35eaf8b..fafe777428a0 100644 --- a/authfd.c +++ b/authfd.c @@ -97,7 +97,13 @@ ssh_get_authentication_socket_path(const char *authsocket, int *fdp) sunaddr.sun_family = AF_UNIX; strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); - if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + #ifdef HAVE_AFUNIX_H + sock = w32_afunix_socket(&sunaddr); + #else + sock = socket(AF_UNIX, SOCK_STREAM, 0); + #endif + + if (sock == -1) return SSH_ERR_SYSTEM_ERROR; /* close on exec */ diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index e6b13a10294d..d945e202f3ea 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1526,6 +1526,9 @@ /* Use PIPES instead of a socketpair() */ #define USE_PIPES 1 +/* Define name for the ssh-agent Windows named pipe */ +#define AGENT_PIPE_ID L"\\\\.\\pipe\\openssh-ssh-agent" + /* define 1 if afunix.h is available */ #define HAVE_AFUNIX_H 1 diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index a6f2d64a56b4..f50bc58c1443 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -43,8 +43,6 @@ HANDLE sshagent_client_primary_token; static HANDLE ioc_port = NULL; static BOOL debug_mode = FALSE; -#define AGENT_PIPE_ID L"\\\\.\\pipe\\openssh-ssh-agent" - static HANDLE event_stop_agent; static OVERLAPPED ol; static HANDLE pipe; diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index d3c6fbe26c7e..732c1c4b5094 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -300,12 +300,6 @@ w32_socket(int domain, int type, int protocol) if (min_index == -1) return -1; - #ifdef HAVE_AFUNIX_H - pio = socketio_socket(domain, type, protocol); - if (pio == NULL) - return -1; - pio->type = SOCK_FD; - #else if (domain == AF_UNIX && type == SOCK_STREAM) { pio = fileio_afunix_socket(); if (pio == NULL) @@ -317,7 +311,65 @@ w32_socket(int domain, int type, int protocol) return -1; pio->type = SOCK_FD; } + + fd_table_set(pio, min_index); + debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); + return min_index; +} + +int +w32_afunix_socket(struct sockaddr_un* addr) +{ + #ifdef HAVE_AFUNIX_H + /* + If HAVE_AFUNIX_H is defined, we can be dealing with the ssh-agent named pipe or + a AF_UNIX socket if ssh forwarding is enabled. If the addr->sun_path is the + the well known named pipe, we open the socket with w32_fileio. + */ + if(strcmp(addr->sun_path, "\\\\.\\pipe\\openssh-ssh-agent") == 0) + return w32_fileio_socket(SOCK_STREAM, 0); + else + return w32_unix_socket(SOCK_STREAM, 0); + #else + return w32_socket(AF_UNIX, SOCK_STREAM, 0); #endif +} + +int +w32_unix_socket(int type, int protocol) +{ + int domain = AF_UNIX; + int min_index = fd_table_get_min_index(); + struct w32_io* pio = NULL; + + errno = 0; + if (min_index == -1) + return -1; + + pio = socketio_socket(domain, type, protocol); + if (pio == NULL) + return -1; + pio->type = SOCK_FD; + + fd_table_set(pio, min_index); + debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); + return min_index; +} + +int +w32_fileio_socket(int type, int protocol) +{ + int min_index = fd_table_get_min_index(); + struct w32_io* pio = NULL; + + errno = 0; + if (min_index == -1) + return -1; + + pio = fileio_afunix_socket(); + if (pio == NULL) + return -1; + pio->type = NONSOCK_FD; fd_table_set(pio, min_index); debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index); diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h index 0f1ee3a08f62..c6ced62cf913 100644 --- a/contrib/win32/win32compat/w32fd.h +++ b/contrib/win32/win32compat/w32fd.h @@ -125,6 +125,7 @@ struct w32_io { #define FILETYPE(pio) (GetFileType(WINHANDLE(pio))) extern HANDLE main_thread; +int w32_afunix_socket(struct sockaddr_un* addr); BOOL w32_io_is_blocking(struct w32_io*); BOOL w32_io_is_io_available(struct w32_io* pio, BOOL rd); int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds); diff --git a/misc.c b/misc.c index b187cc27d44c..244d373216b0 100644 --- a/misc.c +++ b/misc.c @@ -1928,7 +1928,11 @@ unix_listener(const char *path, int backlog, int unlink_first) return -1; } + #ifdef HAVE_AFUNIX_H + sock = w32_afunix_socket(&sunaddr); + #else sock = socket(PF_UNIX, SOCK_STREAM, 0); + #endif if (sock == -1) { saved_errno = errno; error_f("socket: %.100s", strerror(errno)); diff --git a/mux.c b/mux.c index e7580ac742ab..c1ac0d2b5586 100644 --- a/mux.c +++ b/mux.c @@ -2268,7 +2268,13 @@ muxclient(const char *path) fatal("ControlPath too long ('%s' >= %u bytes)", path, (unsigned int)sizeof(addr.sun_path)); - if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) + #ifdef HAVE_AFUNIX_H + sock = w32_afunix_socket(&addr); + #elif + sock = socket(PF_UNIX, SOCK_STREAM, 0); + #endif + + if (sock == -1) fatal_f("socket(): %s", strerror(errno)); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { From 6cc801b79b60664651d4bc9923fa9ec346567238 Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Sat, 15 Apr 2023 04:31:56 +0800 Subject: [PATCH 05/10] Comment regress/cfgmatch.sh temporary --- regress/cfgmatch.sh | 360 ++++++++++++++++++++++---------------------- 1 file changed, 180 insertions(+), 180 deletions(-) diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh index d6931bb1b692..b125bf5536c2 100644 --- a/regress/cfgmatch.sh +++ b/regress/cfgmatch.sh @@ -1,183 +1,183 @@ # $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ # Placed in the Public Domain. -tid="sshd_config match" - -pidfile=$OBJ/remote_pid -fwdport=3301 -fwd="-L $fwdport:127.0.0.1:$PORT" - -echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_config -echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_proxy - -start_client() -{ - rm -f $pidfile - ${SSH} -q $fwd "$@" somehost \ - exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' \ - >>$TEST_REGRESS_LOGFILE 2>&1 & - client_pid=$! - # Wait for remote end - n=0 - while test ! -f $pidfile ; do - sleep 1 - n=`expr $n + 1` - if test $n -gt 60; then - if [ "$os" == "windows" ]; then - # We can't kill windows process from cygwin / wsl so use "stop-process" - powershell.exe /c "stop-process -id $client_pid -Force" >/dev/null 2>&1 - else - kill $client_pid - fi - fatal "timeout waiting for background ssh" - fi - done -} - -stop_client() -{ - pid=`cat $pidfile` - if [ "$os" == "windows" ]; then - # We can't kill windows process from cygwin / wsl so use "stop-process" - powershell.exe /c "stop-process -id $pid -Force" >/dev/null 2>&1 - powershell.exe /c "stop-process -name sleep -Force" >/dev/null 2>&1 - else - if [ ! -z "$pid" ]; then - kill $pid - fi - wait - fi -} - -cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak -echo "PermitOpen 127.0.0.1:1 # comment" >>$OBJ/sshd_config -echo "Match Address 127.0.0.1" >>$OBJ/sshd_config -echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config - -grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy -echo "AuthorizedKeysFile /dev/null # comment" >>$OBJ/sshd_proxy -echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy -if [ "$os" == "windows" ]; then - # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" - echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy -else - echo "Match user $USER" >>$OBJ/sshd_proxy -fi - -echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy -echo "Match Address 127.0.0.1 # comment" >>$OBJ/sshd_proxy -echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy - -${SUDO} ${SSHD} -f $OBJ/sshd_config -T >/dev/null || \ - fail "config w/match fails config test" - -start_sshd - -# Test Match + PermitOpen in sshd_config. This should be permitted -trace "match permitopen localhost" -start_client -F $OBJ/ssh_config -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ - fail "match permitopen permit" -stop_client - -# Same but from different source. This should not be permitted -trace "match permitopen proxy" -start_client -F $OBJ/ssh_proxy -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ - fail "match permitopen deny" -stop_client - -# Retry previous with key option, should also be denied. -cp /dev/null $OBJ/authorized_keys_$USER -for t in ${SSH_KEYTYPES}; do - printf 'permitopen="127.0.0.1:'$PORT'" ' >> $OBJ/authorized_keys_$USER - cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER -done -trace "match permitopen proxy w/key opts" -start_client -F $OBJ/ssh_proxy -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ - fail "match permitopen deny w/key opt" -stop_client - -# Test both sshd_config and key options permitting the same dst/port pair. -# Should be permitted. -trace "match permitopen localhost" -start_client -F $OBJ/ssh_config -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ - fail "match permitopen permit" -stop_client - -cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy -echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy -if [ "$os" == "windows" ]; then - # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" - echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy -else - echo "Match user $USER" >>$OBJ/sshd_proxy -fi -echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy - -# Test that a Match overrides a PermitOpen in the global section -trace "match permitopen proxy w/key opts" -start_client -F $OBJ/ssh_proxy -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ - fail "match override permitopen" -stop_client - -cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy -echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy -echo "Match User NoSuchUser" >>$OBJ/sshd_proxy -echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy - -# Test that a rule that doesn't match doesn't override, plus test a -# PermitOpen entry that's not at the start of the list -trace "nomatch permitopen proxy w/key opts" -start_client -F $OBJ/ssh_proxy -${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ - fail "nomatch override permitopen" -stop_client - -# Test parsing of available Match criteria (with the exception of Group which -# requires knowledge of actual group memberships user running the test). -params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ - localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" -cp $OBJ/sshd_proxy_bak $OBJ/sshd_config -echo 'Banner /nomatch' >>$OBJ/sshd_config -for i in $params; do - config=`echo $i | cut -f1 -d:` - criteria=`echo $i | cut -f2 -d:` - value=`echo $i | cut -f3 -d:` - cat >>$OBJ/sshd_config </dev/null || \ - fail "validate config for w/out spec" - -# Test matching each criteria. -for i in $params; do - testcriteria=`echo $i | cut -f2 -d:` - expected=/`echo $i | cut -f3 -d:` - spec="" - for j in $params; do - config=`echo $j | cut -f1 -d:` - criteria=`echo $j | cut -f2 -d:` - value=`echo $j | cut -f3 -d:` - if [ "$criteria" = "$testcriteria" ]; then - spec="$criteria=$value,$spec" - else - spec="$criteria=1$value,$spec" - fi - done - trace "test spec $spec" - result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ - awk '$1=="banner"{print $2}'` - if [ "$os" == "windows" ]; then - result=${result/$'\r'/} # remove CR (carriage return) - fi - if [ "$result" != "$expected" ]; then - fail "match $config expected $expected got $result" - fi -done +# tid="sshd_config match" + +# pidfile=$OBJ/remote_pid +# fwdport=3301 +# fwd="-L $fwdport:127.0.0.1:$PORT" + +# echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_config +# echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_proxy + +# start_client() +# { +# rm -f $pidfile +# ${SSH} -q $fwd "$@" somehost \ +# exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' \ +# >>$TEST_REGRESS_LOGFILE 2>&1 & +# client_pid=$! +# # Wait for remote end +# n=0 +# while test ! -f $pidfile ; do +# sleep 1 +# n=`expr $n + 1` +# if test $n -gt 60; then +# if [ "$os" == "windows" ]; then +# # We can't kill windows process from cygwin / wsl so use "stop-process" +# powershell.exe /c "stop-process -id $client_pid -Force" >/dev/null 2>&1 +# else +# kill $client_pid +# fi +# fatal "timeout waiting for background ssh" +# fi +# done +# } + +# stop_client() +# { +# pid=`cat $pidfile` +# if [ "$os" == "windows" ]; then +# # We can't kill windows process from cygwin / wsl so use "stop-process" +# powershell.exe /c "stop-process -id $pid -Force" >/dev/null 2>&1 +# powershell.exe /c "stop-process -name sleep -Force" >/dev/null 2>&1 +# else +# if [ ! -z "$pid" ]; then +# kill $pid +# fi +# wait +# fi +# } + +# cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak +# echo "PermitOpen 127.0.0.1:1 # comment" >>$OBJ/sshd_config +# echo "Match Address 127.0.0.1" >>$OBJ/sshd_config +# echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config + +# grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy +# echo "AuthorizedKeysFile /dev/null # comment" >>$OBJ/sshd_proxy +# echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy +# if [ "$os" == "windows" ]; then +# # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" +# echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy +# else +# echo "Match user $USER" >>$OBJ/sshd_proxy +# fi + +# echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy +# echo "Match Address 127.0.0.1 # comment" >>$OBJ/sshd_proxy +# echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy + +# ${SUDO} ${SSHD} -f $OBJ/sshd_config -T >/dev/null || \ +# fail "config w/match fails config test" + +# start_sshd + +# # Test Match + PermitOpen in sshd_config. This should be permitted +# trace "match permitopen localhost" +# start_client -F $OBJ/ssh_config +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ +# fail "match permitopen permit" +# stop_client + +# # Same but from different source. This should not be permitted +# trace "match permitopen proxy" +# start_client -F $OBJ/ssh_proxy +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ +# fail "match permitopen deny" +# stop_client + +# # Retry previous with key option, should also be denied. +# cp /dev/null $OBJ/authorized_keys_$USER +# for t in ${SSH_KEYTYPES}; do +# printf 'permitopen="127.0.0.1:'$PORT'" ' >> $OBJ/authorized_keys_$USER +# cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER +# done +# trace "match permitopen proxy w/key opts" +# start_client -F $OBJ/ssh_proxy +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ +# fail "match permitopen deny w/key opt" +# stop_client + +# # Test both sshd_config and key options permitting the same dst/port pair. +# # Should be permitted. +# trace "match permitopen localhost" +# start_client -F $OBJ/ssh_config +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ +# fail "match permitopen permit" +# stop_client + +# cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy +# echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy +# if [ "$os" == "windows" ]; then +# # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" +# echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy +# else +# echo "Match user $USER" >>$OBJ/sshd_proxy +# fi +# echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy + +# # Test that a Match overrides a PermitOpen in the global section +# trace "match permitopen proxy w/key opts" +# start_client -F $OBJ/ssh_proxy +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ +# fail "match override permitopen" +# stop_client + +# cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy +# echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy +# echo "Match User NoSuchUser" >>$OBJ/sshd_proxy +# echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy + +# # Test that a rule that doesn't match doesn't override, plus test a +# # PermitOpen entry that's not at the start of the list +# trace "nomatch permitopen proxy w/key opts" +# start_client -F $OBJ/ssh_proxy +# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ +# fail "nomatch override permitopen" +# stop_client + +# # Test parsing of available Match criteria (with the exception of Group which +# # requires knowledge of actual group memberships user running the test). +# params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ +# localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" +# cp $OBJ/sshd_proxy_bak $OBJ/sshd_config +# echo 'Banner /nomatch' >>$OBJ/sshd_config +# for i in $params; do +# config=`echo $i | cut -f1 -d:` +# criteria=`echo $i | cut -f2 -d:` +# value=`echo $i | cut -f3 -d:` +# cat >>$OBJ/sshd_config </dev/null || \ +# fail "validate config for w/out spec" + +# # Test matching each criteria. +# for i in $params; do +# testcriteria=`echo $i | cut -f2 -d:` +# expected=/`echo $i | cut -f3 -d:` +# spec="" +# for j in $params; do +# config=`echo $j | cut -f1 -d:` +# criteria=`echo $j | cut -f2 -d:` +# value=`echo $j | cut -f3 -d:` +# if [ "$criteria" = "$testcriteria" ]; then +# spec="$criteria=$value,$spec" +# else +# spec="$criteria=1$value,$spec" +# fi +# done +# trace "test spec $spec" +# result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ +# awk '$1=="banner"{print $2}'` +# if [ "$os" == "windows" ]; then +# result=${result/$'\r'/} # remove CR (carriage return) +# fi +# if [ "$result" != "$expected" ]; then +# fail "match $config expected $expected got $result" +# fi +# done From 705ed7ed4f8063b7915f3b81db3eaa18b140a79a Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Sat, 15 Apr 2023 04:34:48 +0800 Subject: [PATCH 06/10] Add back regress/cfgmatch.sh --- regress/cfgmatch.sh | 366 ++++++++++++++++++++++---------------------- 1 file changed, 183 insertions(+), 183 deletions(-) diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh index b125bf5536c2..a8e335654703 100644 --- a/regress/cfgmatch.sh +++ b/regress/cfgmatch.sh @@ -1,183 +1,183 @@ -# $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ -# Placed in the Public Domain. - -# tid="sshd_config match" - -# pidfile=$OBJ/remote_pid -# fwdport=3301 -# fwd="-L $fwdport:127.0.0.1:$PORT" - -# echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_config -# echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_proxy - -# start_client() -# { -# rm -f $pidfile -# ${SSH} -q $fwd "$@" somehost \ -# exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' \ -# >>$TEST_REGRESS_LOGFILE 2>&1 & -# client_pid=$! -# # Wait for remote end -# n=0 -# while test ! -f $pidfile ; do -# sleep 1 -# n=`expr $n + 1` -# if test $n -gt 60; then -# if [ "$os" == "windows" ]; then -# # We can't kill windows process from cygwin / wsl so use "stop-process" -# powershell.exe /c "stop-process -id $client_pid -Force" >/dev/null 2>&1 -# else -# kill $client_pid -# fi -# fatal "timeout waiting for background ssh" -# fi -# done -# } - -# stop_client() -# { -# pid=`cat $pidfile` -# if [ "$os" == "windows" ]; then -# # We can't kill windows process from cygwin / wsl so use "stop-process" -# powershell.exe /c "stop-process -id $pid -Force" >/dev/null 2>&1 -# powershell.exe /c "stop-process -name sleep -Force" >/dev/null 2>&1 -# else -# if [ ! -z "$pid" ]; then -# kill $pid -# fi -# wait -# fi -# } - -# cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak -# echo "PermitOpen 127.0.0.1:1 # comment" >>$OBJ/sshd_config -# echo "Match Address 127.0.0.1" >>$OBJ/sshd_config -# echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config - -# grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy -# echo "AuthorizedKeysFile /dev/null # comment" >>$OBJ/sshd_proxy -# echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy -# if [ "$os" == "windows" ]; then -# # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" -# echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy -# else -# echo "Match user $USER" >>$OBJ/sshd_proxy -# fi - -# echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy -# echo "Match Address 127.0.0.1 # comment" >>$OBJ/sshd_proxy -# echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy - -# ${SUDO} ${SSHD} -f $OBJ/sshd_config -T >/dev/null || \ -# fail "config w/match fails config test" - -# start_sshd - -# # Test Match + PermitOpen in sshd_config. This should be permitted -# trace "match permitopen localhost" -# start_client -F $OBJ/ssh_config -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ -# fail "match permitopen permit" -# stop_client - -# # Same but from different source. This should not be permitted -# trace "match permitopen proxy" -# start_client -F $OBJ/ssh_proxy -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ -# fail "match permitopen deny" -# stop_client - -# # Retry previous with key option, should also be denied. -# cp /dev/null $OBJ/authorized_keys_$USER -# for t in ${SSH_KEYTYPES}; do -# printf 'permitopen="127.0.0.1:'$PORT'" ' >> $OBJ/authorized_keys_$USER -# cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER -# done -# trace "match permitopen proxy w/key opts" -# start_client -F $OBJ/ssh_proxy -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ -# fail "match permitopen deny w/key opt" -# stop_client - -# # Test both sshd_config and key options permitting the same dst/port pair. -# # Should be permitted. -# trace "match permitopen localhost" -# start_client -F $OBJ/ssh_config -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ -# fail "match permitopen permit" -# stop_client - -# cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy -# echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy -# if [ "$os" == "windows" ]; then -# # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" -# echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy -# else -# echo "Match user $USER" >>$OBJ/sshd_proxy -# fi -# echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy - -# # Test that a Match overrides a PermitOpen in the global section -# trace "match permitopen proxy w/key opts" -# start_client -F $OBJ/ssh_proxy -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ -# fail "match override permitopen" -# stop_client - -# cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy -# echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy -# echo "Match User NoSuchUser" >>$OBJ/sshd_proxy -# echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy - -# # Test that a rule that doesn't match doesn't override, plus test a -# # PermitOpen entry that's not at the start of the list -# trace "nomatch permitopen proxy w/key opts" -# start_client -F $OBJ/ssh_proxy -# ${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ -# fail "nomatch override permitopen" -# stop_client - -# # Test parsing of available Match criteria (with the exception of Group which -# # requires knowledge of actual group memberships user running the test). -# params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ -# localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" -# cp $OBJ/sshd_proxy_bak $OBJ/sshd_config -# echo 'Banner /nomatch' >>$OBJ/sshd_config -# for i in $params; do -# config=`echo $i | cut -f1 -d:` -# criteria=`echo $i | cut -f2 -d:` -# value=`echo $i | cut -f3 -d:` -# cat >>$OBJ/sshd_config </dev/null || \ -# fail "validate config for w/out spec" - -# # Test matching each criteria. -# for i in $params; do -# testcriteria=`echo $i | cut -f2 -d:` -# expected=/`echo $i | cut -f3 -d:` -# spec="" -# for j in $params; do -# config=`echo $j | cut -f1 -d:` -# criteria=`echo $j | cut -f2 -d:` -# value=`echo $j | cut -f3 -d:` -# if [ "$criteria" = "$testcriteria" ]; then -# spec="$criteria=$value,$spec" -# else -# spec="$criteria=1$value,$spec" -# fi -# done -# trace "test spec $spec" -# result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ -# awk '$1=="banner"{print $2}'` -# if [ "$os" == "windows" ]; then -# result=${result/$'\r'/} # remove CR (carriage return) -# fi -# if [ "$result" != "$expected" ]; then -# fail "match $config expected $expected got $result" -# fi -# done + $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ + Placed in the Public Domain. + +tid="sshd_config match" + +pidfile=$OBJ/remote_pid +fwdport=3301 +fwd="-L $fwdport:127.0.0.1:$PORT" + +echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_config +echo "ExitOnForwardFailure=yes" >> $OBJ/ssh_proxy + +start_client() +{ + rm -f $pidfile + ${SSH} -q $fwd "$@" somehost \ + exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' \ + >>$TEST_REGRESS_LOGFILE 2>&1 & + client_pid=$! + # Wait for remote end + n=0 + while test ! -f $pidfile ; do + sleep 1 + n=`expr $n + 1` + if test $n -gt 60; then + if [ "$os" == "windows" ]; then + # We can't kill windows process from cygwin / wsl so use "stop-process" + powershell.exe /c "stop-process -id $client_pid -Force" >/dev/null 2>&1 + else + kill $client_pid + fi + fatal "timeout waiting for background ssh" + fi + done +} + +stop_client() +{ + pid=`cat $pidfile` + if [ "$os" == "windows" ]; then + # We can't kill windows process from cygwin / wsl so use "stop-process" + powershell.exe /c "stop-process -id $pid -Force" >/dev/null 2>&1 + powershell.exe /c "stop-process -name sleep -Force" >/dev/null 2>&1 + else + if [ ! -z "$pid" ]; then + kill $pid + fi + wait + fi +} + +cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak +echo "PermitOpen 127.0.0.1:1 # comment" >>$OBJ/sshd_config +echo "Match Address 127.0.0.1" >>$OBJ/sshd_config +echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config + +grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy +echo "AuthorizedKeysFile /dev/null # comment" >>$OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy +if [ "$os" == "windows" ]; then + # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" + echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy +else + echo "Match user $USER" >>$OBJ/sshd_proxy +fi + +echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy +echo "Match Address 127.0.0.1 # comment" >>$OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy + +${SUDO} ${SSHD} -f $OBJ/sshd_config -T >/dev/null || \ + fail "config w/match fails config test" + +start_sshd + +# Test Match + PermitOpen in sshd_config. This should be permitted +trace "match permitopen localhost" +start_client -F $OBJ/ssh_config +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ + fail "match permitopen permit" +stop_client + +# Same but from different source. This should not be permitted +trace "match permitopen proxy" +start_client -F $OBJ/ssh_proxy +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ + fail "match permitopen deny" +stop_client + +# Retry previous with key option, should also be denied. +cp /dev/null $OBJ/authorized_keys_$USER +for t in ${SSH_KEYTYPES}; do + printf 'permitopen="127.0.0.1:'$PORT'" ' >> $OBJ/authorized_keys_$USER + cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER +done +trace "match permitopen proxy w/key opts" +start_client -F $OBJ/ssh_proxy +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ + fail "match permitopen deny w/key opt" +stop_client + +# Test both sshd_config and key options permitting the same dst/port pair. +# Should be permitted. +trace "match permitopen localhost" +start_client -F $OBJ/ssh_config +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ + fail "match permitopen permit" +stop_client + +cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy +if [ "$os" == "windows" ]; then + # If User is domainuser then it will be in "domain/user" so convert it to "domain\user" + echo "Match user ${USER//\//\\}" >>$OBJ/sshd_proxy +else + echo "Match user $USER" >>$OBJ/sshd_proxy +fi +echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy + +# Test that a Match overrides a PermitOpen in the global section +trace "match permitopen proxy w/key opts" +start_client -F $OBJ/ssh_proxy +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true && \ + fail "match override permitopen" +stop_client + +cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy +echo "Match User NoSuchUser" >>$OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy + +# Test that a rule that doesn't match doesn't override, plus test a +# PermitOpen entry that's not at the start of the list +trace "nomatch permitopen proxy w/key opts" +start_client -F $OBJ/ssh_proxy +${SSH} -q -p $fwdport -F $OBJ/ssh_config somehost true || \ + fail "nomatch override permitopen" +stop_client + +# Test parsing of available Match criteria (with the exception of Group which +# requires knowledge of actual group memberships user running the test). +params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ + localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" +cp $OBJ/sshd_proxy_bak $OBJ/sshd_config +echo 'Banner /nomatch' >>$OBJ/sshd_config +for i in $params; do + config=`echo $i | cut -f1 -d:` + criteria=`echo $i | cut -f2 -d:` + value=`echo $i | cut -f3 -d:` + cat >>$OBJ/sshd_config </dev/null || \ + fail "validate config for w/out spec" + +# Test matching each criteria. +for i in $params; do + testcriteria=`echo $i | cut -f2 -d:` + expected=/`echo $i | cut -f3 -d:` + spec="" + for j in $params; do + config=`echo $j | cut -f1 -d:` + criteria=`echo $j | cut -f2 -d:` + value=`echo $j | cut -f3 -d:` + if [ "$criteria" = "$testcriteria" ]; then + spec="$criteria=$value,$spec" + else + spec="$criteria=1$value,$spec" + fi + done + trace "test spec $spec" + result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ + awk '$1=="banner"{print $2}'` + if [ "$os" == "windows" ]; then + result=${result/$'\r'/} # remove CR (carriage return) + fi + if [ "$result" != "$expected" ]; then + fail "match $config expected $expected got $result" + fi +done From 8ca026c1bb1963a6d66bc822930d68bdecd4a49a Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Sat, 15 Apr 2023 06:57:17 +0800 Subject: [PATCH 07/10] Fix regress/cgmatch.sh comments --- regress/cfgmatch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh index a8e335654703..d6931bb1b692 100644 --- a/regress/cfgmatch.sh +++ b/regress/cfgmatch.sh @@ -1,5 +1,5 @@ - $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ - Placed in the Public Domain. +# $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ +# Placed in the Public Domain. tid="sshd_config match" From 36e5db5a7cda1b103305e4c4123677912b916cfa Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Wed, 19 Apr 2023 05:15:35 +0800 Subject: [PATCH 08/10] WIP: Add agent.sh tests --- contrib/win32/openssh/bash_tests_iterator.ps1 | 2 +- regress/agent.sh | 228 +++++++++--------- regress/test-exec.sh | 15 +- 3 files changed, 131 insertions(+), 114 deletions(-) diff --git a/contrib/win32/openssh/bash_tests_iterator.ps1 b/contrib/win32/openssh/bash_tests_iterator.ps1 index 570173df715e..5b8849118cf9 100644 --- a/contrib/win32/openssh/bash_tests_iterator.ps1 +++ b/contrib/win32/openssh/bash_tests_iterator.ps1 @@ -186,7 +186,7 @@ try # These are the known failed testcases. # transfer.sh, rekey.sh tests fail on CygWin v3.4.0, but succeeds with v3.3.6 - $known_failed_testcases = @("agent.sh", "key-options.sh", "forward-control.sh", "integrity.sh", "krl.sh", "cert-hostkey.sh", "cert-userkey.sh", "percent.sh", "transfer.sh", "rekey.sh") + $known_failed_testcases = @("key-options.sh", "forward-control.sh", "integrity.sh", "krl.sh", "cert-hostkey.sh", "cert-userkey.sh", "percent.sh", "transfer.sh", "rekey.sh") $known_failed_testcases_skipped = @() $start_time = (Get-Date) diff --git a/regress/agent.sh b/regress/agent.sh index 13f0239a7482..8146c78dc7f6 100644 --- a/regress/agent.sh +++ b/regress/agent.sh @@ -39,6 +39,13 @@ ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/user_ca_key \ trace "overwrite authorized keys" printf '' > $OBJ/authorized_keys_$USER +if [ "$os" == "windows" ]; then + # We are adding the default ssh-rsa key to the agent. Certificate based key don't + # seem to be currently working. + cat $OBJ/ssh-rsa.pub >> $OBJ/authorized_keys_$USER + ${SSHADD} $OBJ/ssh-rsa > /dev/null 2>&1 +fi + for t in ${SSH_KEYTYPES}; do # generate user key for agent rm -f $OBJ/$t-agent $OBJ/$t-agent.pub* @@ -90,6 +97,7 @@ if [ $r -ne 52 ]; then fail "ssh connect with failed (exit code $r)" fi +if [ "$os" != "windows" ]; then for t in ${SSH_KEYTYPES}; do trace "connect via agent using $t key" if [ "$t" = "ssh-dss" ]; then @@ -103,6 +111,7 @@ for t in ${SSH_KEYTYPES}; do fail "ssh connect with failed (exit code $r)" fi done +fi trace "agent forwarding" ${SSH} -A -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 @@ -110,123 +119,126 @@ r=$? if [ $r -ne 0 ]; then fail "ssh-add -l via agent fwd failed (exit code $r)" fi -${SSH} "-oForwardAgent=$SSH_AUTH_SOCK" -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -l via agent path fwd failed (exit code $r)" -fi -${SSH} -A -F $OBJ/ssh_proxy somehost \ - "${SSH} -F $OBJ/ssh_proxy somehost exit 52" -r=$? -if [ $r -ne 52 ]; then - fail "agent fwd failed (exit code $r)" -fi - -trace "agent forwarding different agent" -${SSH} "-oForwardAgent=$FW_SSH_AUTH_SOCK" -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -l via agent path fwd of different agent failed (exit code $r)" -fi -${SSH} '-oForwardAgent=$FW_SSH_AUTH_SOCK' -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -l via agent path env fwd of different agent failed (exit code $r)" -fi - -# Remove keys from forwarded agent, ssh-add on remote machine should now fail. -SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} -D > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -D failed: exit code $r" -fi -${SSH} '-oForwardAgent=$FW_SSH_AUTH_SOCK' -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 1 ]; then - fail "ssh-add -l with different agent did not fail with exit code 1 (exit code $r)" -fi -(printf 'cert-authority,principals="estragon" '; cat $OBJ/user_ca_key.pub) \ - > $OBJ/authorized_keys_$USER -for t in ${SSH_KEYTYPES}; do - if [ "$t" != "ssh-dss" ]; then - trace "connect via agent using $t key" - ${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub \ - -oCertificateFile=$OBJ/$t-agent-cert.pub \ - -oIdentitiesOnly=yes somehost exit 52 +if [ "$os" != "windows" ]; then + ${SSH} "-oForwardAgent=$SSH_AUTH_SOCK" -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -l via agent path fwd failed (exit code $r)" + fi + ${SSH} -A -F $OBJ/ssh_proxy somehost \ + "${SSH} -F $OBJ/ssh_proxy somehost exit 52" r=$? if [ $r -ne 52 ]; then - fail "ssh connect with failed (exit code $r)" + fail "agent fwd failed (exit code $r)" fi - fi -done -## Deletion tests. + trace "agent forwarding different agent" + ${SSH} "-oForwardAgent=$FW_SSH_AUTH_SOCK" -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -l via agent path fwd of different agent failed (exit code $r)" + fi + ${SSH} '-oForwardAgent=$FW_SSH_AUTH_SOCK' -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -l via agent path env fwd of different agent failed (exit code $r)" + fi -trace "delete all agent keys" -${SSHADD} -D > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -D failed: exit code $r" -fi -# make sure they're gone -${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 1 ]; then - fail "ssh-add -l returned unexpected exit code: $r" -fi -trace "readd keys" -# re-add keys/certs to agent -for t in ${SSH_KEYTYPES}; do - ${SSHADD} $OBJ/$t-agent-private >/dev/null 2>&1 || \ - fail "ssh-add failed exit code $?" -done -# make sure they are there -${SSHADD} -l > /dev/null 2>&1 -r=$? -if [ $r -ne 0 ]; then - fail "ssh-add -l failed: exit code $r" -fi + # Remove keys from forwarded agent, ssh-add on remote machine should now fail. + SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} -D > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -D failed: exit code $r" + fi + ${SSH} '-oForwardAgent=$FW_SSH_AUTH_SOCK' -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 1 ]; then + fail "ssh-add -l with different agent did not fail with exit code 1 (exit code $r)" + fi -check_key_absent() { - ${SSHADD} -L | grep "^$1 " >/dev/null - if [ $? -eq 0 ]; then - fail "$1 key unexpectedly present" + (printf 'cert-authority,principals="estragon" '; cat $OBJ/user_ca_key.pub) \ + > $OBJ/authorized_keys_$USER + for t in ${SSH_KEYTYPES}; do + if [ "$t" != "ssh-dss" ]; then + trace "connect via agent using $t key" + ${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub \ + -oCertificateFile=$OBJ/$t-agent-cert.pub \ + -oIdentitiesOnly=yes somehost exit 52 + r=$? + if [ $r -ne 52 ]; then + fail "ssh connect with failed (exit code $r)" + fi + fi + done + + ## Deletion tests. + + trace "delete all agent keys" + ${SSHADD} -D > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -D failed: exit code $r" fi -} -check_key_present() { - ${SSHADD} -L | grep "^$1 " >/dev/null - if [ $? -ne 0 ]; then - fail "$1 key missing from agent" + # make sure they're gone + ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 1 ]; then + fail "ssh-add -l returned unexpected exit code: $r" + fi + trace "readd keys" + # re-add keys/certs to agent + for t in ${SSH_KEYTYPES}; do + ${SSHADD} $OBJ/$t-agent-private >/dev/null 2>&1 || \ + fail "ssh-add failed exit code $?" + done + # make sure they are there + ${SSHADD} -l > /dev/null 2>&1 + r=$? + if [ $r -ne 0 ]; then + fail "ssh-add -l failed: exit code $r" fi -} - -# delete the ed25519 key -trace "delete single key by file" -${SSHADD} -qdk $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed" -check_key_absent ssh-ed25519 -check_key_present ssh-ed25519-cert-v01@openssh.com -# Put key/cert back. -${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \ - fail "ssh-add failed exit code $?" -check_key_present ssh-ed25519 -# Delete both key and certificate. -trace "delete key/cert by file" -${SSHADD} -qd $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed" -check_key_absent ssh-ed25519 -check_key_absent ssh-ed25519-cert-v01@openssh.com -# Put key/cert back. -${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \ - fail "ssh-add failed exit code $?" -check_key_present ssh-ed25519 -# Delete certificate via stdin -${SSHADD} -qd - < $OBJ/ssh-ed25519-agent-cert.pub || fail "ssh-add -d - failed" -check_key_present ssh-ed25519 -check_key_absent ssh-ed25519-cert-v01@openssh.com -# Delete key via stdin -${SSHADD} -qd - < $OBJ/ssh-ed25519-agent.pub || fail "ssh-add -d - failed" -check_key_absent ssh-ed25519 -check_key_absent ssh-ed25519-cert-v01@openssh.com + + check_key_absent() { + ${SSHADD} -L | grep "^$1 " >/dev/null + if [ $? -eq 0 ]; then + fail "$1 key unexpectedly present" + fi + } + check_key_present() { + ${SSHADD} -L | grep "^$1 " >/dev/null + if [ $? -ne 0 ]; then + fail "$1 key missing from agent" + fi + } + + # delete the ed25519 key + trace "delete single key by file" + ${SSHADD} -qdk $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed" + check_key_absent ssh-ed25519 + check_key_present ssh-ed25519-cert-v01@openssh.com + # Put key/cert back. + ${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \ + fail "ssh-add failed exit code $?" + check_key_present ssh-ed25519 + # Delete both key and certificate. + trace "delete key/cert by file" + ${SSHADD} -qd $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed" + check_key_absent ssh-ed25519 + check_key_absent ssh-ed25519-cert-v01@openssh.com + # Put key/cert back. + ${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \ + fail "ssh-add failed exit code $?" + check_key_present ssh-ed25519 + # Delete certificate via stdin + ${SSHADD} -qd - < $OBJ/ssh-ed25519-agent-cert.pub || fail "ssh-add -d - failed" + check_key_present ssh-ed25519 + check_key_absent ssh-ed25519-cert-v01@openssh.com + # Delete key via stdin + ${SSHADD} -qd - < $OBJ/ssh-ed25519-agent.pub || fail "ssh-add -d - failed" + check_key_absent ssh-ed25519 + check_key_absent ssh-ed25519-cert-v01@openssh.com +fi trace "kill agent" ${SSHAGENT} -k > /dev/null diff --git a/regress/test-exec.sh b/regress/test-exec.sh index 2364c7b769e5..c46b9491ece1 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -633,8 +633,8 @@ Host * HostKeyAlias localhost-with-alias Port $PORT User $USER - GlobalKnownHostsFile $OBJ/known_hosts - UserKnownHostsFile $OBJ/known_hosts + GlobalKnownHostsFile `windows_path $OBJ/known_hosts` + UserKnownHostsFile `windows_path $OBJ/known_hosts` PubkeyAuthentication yes ChallengeResponseAuthentication no PasswordAuthentication no @@ -685,6 +685,7 @@ if [ "$os" == "windows" ]; then SSH_KEYTYPES=`echo $SSH_KEYTYPES | tr -d '\r','\n'` # remove \r\n SSH_HOSTKEY_TYPES=`echo $SSH_HOSTKEY_TYPES | tr -d '\r','\n'` # remove \r\n OBJ_WIN_FORMAT=`windows_path $OBJ` + SRC_WIN_FORMAT=`windows_path $SRC` first_key_type=${SSH_KEYTYPES%% *} if [ "x$USER_DOMAIN" != "x" ]; then # For domain user, create folders @@ -733,8 +734,12 @@ for t in ${SSH_HOSTKEY_TYPES}; do echo HostKey $OBJ/host.$t >> $OBJ/sshd_config - # don't use SUDO for proxy connect - echo HostKey $OBJ/$t >> $OBJ/sshd_proxy + if [ "$os" == "windows" ]; then + echo HostKey `windows_path $OBJ/$t` >> $OBJ/sshd_proxy + else + # don't use SUDO for proxy connect + echo HostKey $OBJ/$t >> $OBJ/sshd_proxy + fi done if [ "$os" == "windows" ]; then @@ -804,7 +809,7 @@ fi if [ "$os" == "windows" ]; then # TODO - having SSH_SK_HELPER is causing issues. Need to find a way. # This is fine for now as we don't have FIDO enabled. - echo proxycommand `windows_path ${SSHD}` -i -f $OBJ_WIN_FORMAT/sshd_proxy + echo proxycommand `windows_path ${SSHD}` -i -f `windows_path $OBJ`/sshd_proxy else echo proxycommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy fi From fd096f59a64b2e66f6afa0fb9db491265e9df5d9 Mon Sep 17 00:00:00 2001 From: Martin Fernandez Date: Wed, 19 Apr 2023 12:44:51 +0800 Subject: [PATCH 09/10] Compare with AGENT_PIPE_ID --- contrib/win32/win32compat/w32fd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 732c1c4b5094..534b256b58d7 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -326,7 +326,11 @@ w32_afunix_socket(struct sockaddr_un* addr) a AF_UNIX socket if ssh forwarding is enabled. If the addr->sun_path is the the well known named pipe, we open the socket with w32_fileio. */ - if(strcmp(addr->sun_path, "\\\\.\\pipe\\openssh-ssh-agent") == 0) + int len = wcslen(AGENT_PIPE_ID); + char* pipeid = (char*)malloc(len + 1); + memset(pipeid, 0, len + 1); + + if(wcstombs(pipeid, AGENT_PIPE_ID, len + 1) != (size_t) -1 && strcmp(addr->sun_path, pipeid) == 0) return w32_fileio_socket(SOCK_STREAM, 0); else return w32_unix_socket(SOCK_STREAM, 0); From 0d38b159baba2a14e06416d25a60680561fc664b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Fern=C3=A1ndez?= Date: Tue, 25 Feb 2025 13:44:10 -0300 Subject: [PATCH 10/10] Remove unnecessary HAVE_AFUNIX_H conditions --- authfd.c | 8 +------- misc.c | 7 +------ mux.c | 8 +------- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/authfd.c b/authfd.c index fafe777428a0..6a4446314c3e 100644 --- a/authfd.c +++ b/authfd.c @@ -97,13 +97,7 @@ ssh_get_authentication_socket_path(const char *authsocket, int *fdp) sunaddr.sun_family = AF_UNIX; strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); - #ifdef HAVE_AFUNIX_H - sock = w32_afunix_socket(&sunaddr); - #else - sock = socket(AF_UNIX, SOCK_STREAM, 0); - #endif - - if (sock == -1) + if ((sock = w32_afunix_socket(&sunaddr)) == -1) return SSH_ERR_SYSTEM_ERROR; /* close on exec */ diff --git a/misc.c b/misc.c index 244d373216b0..d276ec704357 100644 --- a/misc.c +++ b/misc.c @@ -1928,12 +1928,7 @@ unix_listener(const char *path, int backlog, int unlink_first) return -1; } - #ifdef HAVE_AFUNIX_H - sock = w32_afunix_socket(&sunaddr); - #else - sock = socket(PF_UNIX, SOCK_STREAM, 0); - #endif - if (sock == -1) { + if ((sock = w32_afunix_socket(&sunaddr)) == -1) { saved_errno = errno; error_f("socket: %.100s", strerror(errno)); errno = saved_errno; diff --git a/mux.c b/mux.c index c1ac0d2b5586..fc9f16c66fae 100644 --- a/mux.c +++ b/mux.c @@ -2268,13 +2268,7 @@ muxclient(const char *path) fatal("ControlPath too long ('%s' >= %u bytes)", path, (unsigned int)sizeof(addr.sun_path)); - #ifdef HAVE_AFUNIX_H - sock = w32_afunix_socket(&addr); - #elif - sock = socket(PF_UNIX, SOCK_STREAM, 0); - #endif - - if (sock == -1) + if ((sock = w32_afunix_socket(&addr)) == -1) fatal_f("socket(): %s", strerror(errno)); if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {