From 5ad8a2c3580ce0bfcf1f81c11b7641235dfcdfea Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Mon, 19 Dec 2016 14:46:28 -0800 Subject: [PATCH] Sources Merged from Win32 Fork --- auth-passwd.c | 39 +- auth.c | 15 + auth2-pubkey.c | 56 + authfd.c | 43 + authfile.c | 3 + buffer.c | 3 + channels.c | 2 + clientloop.c | 4 + contrib/win32/openssh/README.txt | 22 + contrib/win32/openssh/VSWithBuildTools.xml | 84 + contrib/win32/openssh/Win32-OpenSSH.sln | 343 ++++ contrib/win32/openssh/config.h.vs | 1715 +++++++++++++++++ contrib/win32/openssh/config.vcxproj | 204 ++ contrib/win32/openssh/config.vcxproj.filters | 17 + contrib/win32/openssh/install-sshd.ps1 | 43 + contrib/win32/openssh/install-sshlsa.ps1 | 10 + contrib/win32/openssh/keygen.vcxproj | 194 ++ contrib/win32/openssh/keygen.vcxproj.filters | 30 + contrib/win32/openssh/libssh.vcxproj | 296 +++ contrib/win32/openssh/libssh.vcxproj.filters | 300 +++ contrib/win32/openssh/openbsd_compat.vcxproj | 265 +++ .../openssh/openbsd_compat.vcxproj.filters | 303 +++ contrib/win32/openssh/openssh_build.cmd | 4 + contrib/win32/openssh/paths.targets | 14 + contrib/win32/openssh/resource.h | Bin 0 -> 812 bytes contrib/win32/openssh/scp.vcxproj | 192 ++ contrib/win32/openssh/scp.vcxproj.filters | 30 + contrib/win32/openssh/sftp-server.vcxproj | 196 ++ .../win32/openssh/sftp-server.vcxproj.filters | 33 + contrib/win32/openssh/sftp.vcxproj | 198 ++ contrib/win32/openssh/sftp.vcxproj.filters | 42 + contrib/win32/openssh/ssh-add.vcxproj | 197 ++ contrib/win32/openssh/ssh-add.vcxproj.filters | 35 + contrib/win32/openssh/ssh-agent.vcxproj | 220 +++ contrib/win32/openssh/ssh-lsa.def | 11 + contrib/win32/openssh/ssh-lsa.vcxproj | 189 ++ contrib/win32/openssh/ssh-lsa.vcxproj.filters | 27 + contrib/win32/openssh/ssh-shellhost.vcxproj | 188 ++ contrib/win32/openssh/ssh.vcxproj | 308 +++ contrib/win32/openssh/ssh.vcxproj.filters | 320 +++ contrib/win32/openssh/sshd.vcxproj | 254 +++ contrib/win32/openssh/sshd.vcxproj.filters | 159 ++ contrib/win32/openssh/sshd_config | 122 ++ contrib/win32/openssh/targetos.manifest | 17 + contrib/win32/openssh/uninstall-sshd.ps1 | 22 + contrib/win32/openssh/uninstall-sshlsa.ps1 | 10 + contrib/win32/openssh/version.rc | Bin 0 -> 4046 bytes contrib/win32/win32compat/Debug.h | 39 + contrib/win32/win32compat/ansiprsr.c | 1000 ++++++++++ contrib/win32/win32compat/ansiprsr.h | 81 + contrib/win32/win32compat/conio.c | 183 ++ contrib/win32/win32compat/console.c | 1590 +++++++++++++++ contrib/win32/win32compat/console.h | 139 ++ contrib/win32/win32compat/fileio.c | 694 +++++++ contrib/win32/win32compat/inc/arpa/inet.h | 6 + contrib/win32/win32compat/inc/arpa/nameser.h | 6 + contrib/win32/win32compat/inc/crypto-wrap.h | 76 + contrib/win32/win32compat/inc/defs.h | 97 + contrib/win32/win32compat/inc/dirent.h | 25 + contrib/win32/win32compat/inc/dlfcn.h | 11 + contrib/win32/win32compat/inc/fcntl.h | 23 + contrib/win32/win32compat/inc/grp.h | 6 + contrib/win32/win32compat/inc/libgen.h | 3 + contrib/win32/win32compat/inc/netdb.h | 6 + contrib/win32/win32compat/inc/netinet/in.h | 6 + .../win32/win32compat/inc/netinet/in_systm.h | 6 + contrib/win32/win32compat/inc/netinet/ip.h | 6 + contrib/win32/win32compat/inc/netinet/tcp.h | 7 + contrib/win32/win32compat/inc/poll.h | 7 + contrib/win32/win32compat/inc/process.h | 6 + contrib/win32/win32compat/inc/pwd.h | 45 + contrib/win32/win32compat/inc/resolv.h | 6 + contrib/win32/win32compat/inc/signal.h | 43 + contrib/win32/win32compat/inc/sys/ioctl.h | 8 + contrib/win32/win32compat/inc/sys/param.h | 10 + contrib/win32/win32compat/inc/sys/resource.h | 6 + contrib/win32/win32compat/inc/sys/select.h | 13 + contrib/win32/win32compat/inc/sys/socket.h | 24 + contrib/win32/win32compat/inc/sys/stat.h | 64 + contrib/win32/win32compat/inc/sys/statvfs.h | 26 + contrib/win32/win32compat/inc/sys/time.h | 9 + contrib/win32/win32compat/inc/sys/uio.h | 7 + contrib/win32/win32compat/inc/sys/un.h | 7 + contrib/win32/win32compat/inc/sys/wait.h | 19 + contrib/win32/win32compat/inc/syslog.h | 28 + contrib/win32/win32compat/inc/termios.h | 110 ++ contrib/win32/win32compat/inc/unistd.h | 50 + contrib/win32/win32compat/inc/utf.h | 12 + contrib/win32/win32compat/inc/w32posix.h | 161 ++ contrib/win32/win32compat/inc/zlib.h | 76 + contrib/win32/win32compat/libwin32compat.q | 1 + contrib/win32/win32compat/lsa/Ssh-lsa.c | 357 ++++ contrib/win32/win32compat/lsastring.c | 152 ++ contrib/win32/win32compat/lsastring.h | 50 + contrib/win32/win32compat/misc.c | 813 ++++++++ contrib/win32/win32compat/no-ops.c | 129 ++ contrib/win32/win32compat/pwd.c | 298 +++ contrib/win32/win32compat/shell-host.c | 1307 +++++++++++++ contrib/win32/win32compat/signal.c | 310 +++ contrib/win32/win32compat/signal_internal.h | 34 + contrib/win32/win32compat/signal_sigalrm.c | 89 + contrib/win32/win32compat/signal_sigchld.c | 233 +++ contrib/win32/win32compat/socketio.c | 1082 +++++++++++ .../win32/win32compat/ssh-agent/agent-main.c | 159 ++ .../win32compat/ssh-agent/agent-request.h | 21 + contrib/win32/win32compat/ssh-agent/agent.c | 266 +++ contrib/win32/win32compat/ssh-agent/agent.h | 48 + .../win32/win32compat/ssh-agent/agentconfig.c | 132 ++ .../win32compat/ssh-agent/authagent-request.c | 389 ++++ .../win32/win32compat/ssh-agent/connection.c | 236 +++ .../win32compat/ssh-agent/keyagent-request.c | 438 +++++ .../win32/win32compat/ssh_config/ssh_config | 50 + .../win32/win32compat/ssh_config/sshd_config | 122 ++ contrib/win32/win32compat/termio.c | 205 ++ contrib/win32/win32compat/tncon.c | 626 ++++++ contrib/win32/win32compat/tncon.h | 184 ++ contrib/win32/win32compat/tnnet.c | 94 + contrib/win32/win32compat/tnnet.h | 42 + contrib/win32/win32compat/ttymodes_windows.c | 230 +++ contrib/win32/win32compat/w32fd.c | 851 ++++++++ contrib/win32/win32compat/w32fd.h | 161 ++ contrib/win32/win32compat/w32log.c | 56 + contrib/win32/win32compat/win32_dirent.c | 131 ++ contrib/win32/win32compat/win32_zlib.c | 64 + contrib/win32/win32compat/win32compat.vcproj | 311 +++ contrib/win32/win32compat/wmain_common.c | 53 + contrib/win32/win32compat/wmain_sshd.c | 139 ++ defines.h | 5 + dns.c | 5 + hostfile.c | 6 + log.c | 8 + loginrec.c | 1 + misc.c | 25 + myproposal.h | 5 + openbsd-compat/openbsd-compat.h | 3 + progressmeter.c | 5 + readconf.c | 7 + readpass.c | 73 + scp.c | 174 +- servconf.c | 5 + session.c | 366 ++++ sftp.c | 160 ++ ssh-add.c | 5 + ssh-keygen.c | 20 + ssh.c | 9 + sshconnect.c | 21 + sshconnect2.c | 10 + sshd.c | 111 +- sshpty.c | 51 + sshtty.c | 29 + utf8.c | 6 + 151 files changed, 22495 insertions(+), 4 deletions(-) create mode 100644 contrib/win32/openssh/README.txt create mode 100644 contrib/win32/openssh/VSWithBuildTools.xml create mode 100644 contrib/win32/openssh/Win32-OpenSSH.sln create mode 100644 contrib/win32/openssh/config.h.vs create mode 100644 contrib/win32/openssh/config.vcxproj create mode 100644 contrib/win32/openssh/config.vcxproj.filters create mode 100644 contrib/win32/openssh/install-sshd.ps1 create mode 100644 contrib/win32/openssh/install-sshlsa.ps1 create mode 100644 contrib/win32/openssh/keygen.vcxproj create mode 100644 contrib/win32/openssh/keygen.vcxproj.filters create mode 100644 contrib/win32/openssh/libssh.vcxproj create mode 100644 contrib/win32/openssh/libssh.vcxproj.filters create mode 100644 contrib/win32/openssh/openbsd_compat.vcxproj create mode 100644 contrib/win32/openssh/openbsd_compat.vcxproj.filters create mode 100644 contrib/win32/openssh/openssh_build.cmd create mode 100644 contrib/win32/openssh/paths.targets create mode 100644 contrib/win32/openssh/resource.h create mode 100644 contrib/win32/openssh/scp.vcxproj create mode 100644 contrib/win32/openssh/scp.vcxproj.filters create mode 100644 contrib/win32/openssh/sftp-server.vcxproj create mode 100644 contrib/win32/openssh/sftp-server.vcxproj.filters create mode 100644 contrib/win32/openssh/sftp.vcxproj create mode 100644 contrib/win32/openssh/sftp.vcxproj.filters create mode 100644 contrib/win32/openssh/ssh-add.vcxproj create mode 100644 contrib/win32/openssh/ssh-add.vcxproj.filters create mode 100644 contrib/win32/openssh/ssh-agent.vcxproj create mode 100644 contrib/win32/openssh/ssh-lsa.def create mode 100644 contrib/win32/openssh/ssh-lsa.vcxproj create mode 100644 contrib/win32/openssh/ssh-lsa.vcxproj.filters create mode 100644 contrib/win32/openssh/ssh-shellhost.vcxproj create mode 100644 contrib/win32/openssh/ssh.vcxproj create mode 100644 contrib/win32/openssh/ssh.vcxproj.filters create mode 100644 contrib/win32/openssh/sshd.vcxproj create mode 100644 contrib/win32/openssh/sshd.vcxproj.filters create mode 100644 contrib/win32/openssh/sshd_config create mode 100644 contrib/win32/openssh/targetos.manifest create mode 100644 contrib/win32/openssh/uninstall-sshd.ps1 create mode 100644 contrib/win32/openssh/uninstall-sshlsa.ps1 create mode 100644 contrib/win32/openssh/version.rc create mode 100644 contrib/win32/win32compat/Debug.h create mode 100644 contrib/win32/win32compat/ansiprsr.c create mode 100644 contrib/win32/win32compat/ansiprsr.h create mode 100644 contrib/win32/win32compat/conio.c create mode 100644 contrib/win32/win32compat/console.c create mode 100644 contrib/win32/win32compat/console.h create mode 100644 contrib/win32/win32compat/fileio.c create mode 100644 contrib/win32/win32compat/inc/arpa/inet.h create mode 100644 contrib/win32/win32compat/inc/arpa/nameser.h create mode 100644 contrib/win32/win32compat/inc/crypto-wrap.h create mode 100644 contrib/win32/win32compat/inc/defs.h create mode 100644 contrib/win32/win32compat/inc/dirent.h create mode 100644 contrib/win32/win32compat/inc/dlfcn.h create mode 100644 contrib/win32/win32compat/inc/fcntl.h create mode 100644 contrib/win32/win32compat/inc/grp.h create mode 100644 contrib/win32/win32compat/inc/libgen.h create mode 100644 contrib/win32/win32compat/inc/netdb.h create mode 100644 contrib/win32/win32compat/inc/netinet/in.h create mode 100644 contrib/win32/win32compat/inc/netinet/in_systm.h create mode 100644 contrib/win32/win32compat/inc/netinet/ip.h create mode 100644 contrib/win32/win32compat/inc/netinet/tcp.h create mode 100644 contrib/win32/win32compat/inc/poll.h create mode 100644 contrib/win32/win32compat/inc/process.h create mode 100644 contrib/win32/win32compat/inc/pwd.h create mode 100644 contrib/win32/win32compat/inc/resolv.h create mode 100644 contrib/win32/win32compat/inc/signal.h create mode 100644 contrib/win32/win32compat/inc/sys/ioctl.h create mode 100644 contrib/win32/win32compat/inc/sys/param.h create mode 100644 contrib/win32/win32compat/inc/sys/resource.h create mode 100644 contrib/win32/win32compat/inc/sys/select.h create mode 100644 contrib/win32/win32compat/inc/sys/socket.h create mode 100644 contrib/win32/win32compat/inc/sys/stat.h create mode 100644 contrib/win32/win32compat/inc/sys/statvfs.h create mode 100644 contrib/win32/win32compat/inc/sys/time.h create mode 100644 contrib/win32/win32compat/inc/sys/uio.h create mode 100644 contrib/win32/win32compat/inc/sys/un.h create mode 100644 contrib/win32/win32compat/inc/sys/wait.h create mode 100644 contrib/win32/win32compat/inc/syslog.h create mode 100644 contrib/win32/win32compat/inc/termios.h create mode 100644 contrib/win32/win32compat/inc/unistd.h create mode 100644 contrib/win32/win32compat/inc/utf.h create mode 100644 contrib/win32/win32compat/inc/w32posix.h create mode 100644 contrib/win32/win32compat/inc/zlib.h create mode 100644 contrib/win32/win32compat/libwin32compat.q create mode 100644 contrib/win32/win32compat/lsa/Ssh-lsa.c create mode 100644 contrib/win32/win32compat/lsastring.c create mode 100644 contrib/win32/win32compat/lsastring.h create mode 100644 contrib/win32/win32compat/misc.c create mode 100644 contrib/win32/win32compat/no-ops.c create mode 100644 contrib/win32/win32compat/pwd.c create mode 100644 contrib/win32/win32compat/shell-host.c create mode 100644 contrib/win32/win32compat/signal.c create mode 100644 contrib/win32/win32compat/signal_internal.h create mode 100644 contrib/win32/win32compat/signal_sigalrm.c create mode 100644 contrib/win32/win32compat/signal_sigchld.c create mode 100644 contrib/win32/win32compat/socketio.c create mode 100644 contrib/win32/win32compat/ssh-agent/agent-main.c create mode 100644 contrib/win32/win32compat/ssh-agent/agent-request.h create mode 100644 contrib/win32/win32compat/ssh-agent/agent.c create mode 100644 contrib/win32/win32compat/ssh-agent/agent.h create mode 100644 contrib/win32/win32compat/ssh-agent/agentconfig.c create mode 100644 contrib/win32/win32compat/ssh-agent/authagent-request.c create mode 100644 contrib/win32/win32compat/ssh-agent/connection.c create mode 100644 contrib/win32/win32compat/ssh-agent/keyagent-request.c create mode 100644 contrib/win32/win32compat/ssh_config/ssh_config create mode 100644 contrib/win32/win32compat/ssh_config/sshd_config create mode 100644 contrib/win32/win32compat/termio.c create mode 100644 contrib/win32/win32compat/tncon.c create mode 100644 contrib/win32/win32compat/tncon.h create mode 100644 contrib/win32/win32compat/tnnet.c create mode 100644 contrib/win32/win32compat/tnnet.h create mode 100644 contrib/win32/win32compat/ttymodes_windows.c create mode 100644 contrib/win32/win32compat/w32fd.c create mode 100644 contrib/win32/win32compat/w32fd.h create mode 100644 contrib/win32/win32compat/w32log.c create mode 100644 contrib/win32/win32compat/win32_dirent.c create mode 100644 contrib/win32/win32compat/win32_zlib.c create mode 100644 contrib/win32/win32compat/win32compat.vcproj create mode 100644 contrib/win32/win32compat/wmain_common.c create mode 100644 contrib/win32/win32compat/wmain_sshd.c diff --git a/auth-passwd.c b/auth-passwd.c index 996c2cf71..3b81c2d68 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -222,4 +222,41 @@ sys_auth_passwd(Authctxt *authctxt, const char *password) return encrypted_password != NULL && strcmp(encrypted_password, pw_password) == 0; } -#endif + +#elif defined(WINDOWS) +/* +* Authenticate on Windows - Pass creds to ssh-agent and retrieve token +* upon succesful authentication +*/ +extern int auth_sock; +int sys_auth_passwd(Authctxt *authctxt, const char *password) +{ + u_char *blob = NULL; + size_t blen = 0; + DWORD token = 0; + struct sshbuf *msg = NULL; + + msg = sshbuf_new(); + if (!msg) + return 0; + if (sshbuf_put_u8(msg, 100) != 0 || + sshbuf_put_cstring(msg, "password") != 0 || + sshbuf_put_cstring(msg, authctxt->user) != 0 || + sshbuf_put_cstring(msg, password) != 0 || + ssh_request_reply(auth_sock, msg, msg) != 0 || + sshbuf_get_u32(msg, &token) != 0) { + debug("auth agent did not authorize client %s", authctxt->pw->pw_name); + return 0; + } + + + if (blob) + free(blob); + if (msg) + sshbuf_free(msg); + + authctxt->methoddata = (void*)(INT_PTR)token; + + return 1; +} +#endif /* WINDOWS */ diff --git a/auth.c b/auth.c index 6ee6116df..a6ba4d457 100644 --- a/auth.c +++ b/auth.c @@ -489,6 +489,10 @@ int auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, uid_t uid, char *err, size_t errlen) { +#ifdef WINDOWS + error("auth_secure_path should not be called in Windows"); + return -1; +#else /* !WINDOWS */ char buf[PATH_MAX], homedir[PATH_MAX]; char *cp; int comparehome = 0; @@ -541,6 +545,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, break; } return 0; +#endif /* !WINDOWS */ } /* @@ -573,6 +578,15 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes, int fd; FILE *f; +#ifdef WINDOWS + /* Windows POSIX adpater does not support fdopen() on open(file)*/ + if ((f = fopen(file, "r")) == NULL) { + debug("Could not open %s '%s': %s", file_type, file, + strerror(errno)); + return NULL; + } + /* TODO check permissions */ +#else /* !WINDOWS */ if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { if (log_missing || errno != ENOENT) debug("Could not open %s '%s': %s", file_type, file, @@ -602,6 +616,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes, auth_debug_add("Ignored %s: %s", file_type, line); return NULL; } +#endif /* !WINDOWS */ return f; } diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 20f3309e1..949a864ac 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -175,6 +175,51 @@ userauth_pubkey(Authctxt *authctxt) /* test for correct signature */ authenticated = 0; + +#ifdef WINDOWS + /* Pass key challenge material to ssh-agent to retrieve token upon succesful authentication */ + { + extern int auth_sock; + int r; + u_char *blob = NULL; + size_t blen = 0; + DWORD token = 0; + struct sshbuf *msg = NULL; + + while (1) { + msg = sshbuf_new(); + if (!msg) + break; + if ((r = sshbuf_put_u8(msg, 100)) != 0 || + (r = sshbuf_put_cstring(msg, "pubkey")) != 0 || + (r = sshkey_to_blob(key, &blob, &blen)) != 0 || + (r = sshbuf_put_string(msg, blob, blen)) != 0 || + (r = sshbuf_put_cstring(msg, authctxt->pw->pw_name)) != 0 || + (r = sshbuf_put_string(msg, sig, slen)) != 0 || + (r = sshbuf_put_string(msg, buffer_ptr(&b), buffer_len(&b))) != 0 || + (r = ssh_request_reply(auth_sock, msg, msg)) != 0 || + (r = sshbuf_get_u32(msg, &token)) != 0) { + debug("auth agent did not authorize client %s", authctxt->pw->pw_name); + break; + } + + debug3("auth agent authenticated %s", authctxt->pw->pw_name); + break; + + } + if (blob) + free(blob); + if (msg) + sshbuf_free(msg); + + if (token) { + authenticated = 1; + authctxt->methoddata = (void*)(INT_PTR)token; + } + + } + +#else /* !WINDOWS */ if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) { @@ -185,6 +230,8 @@ userauth_pubkey(Authctxt *authctxt) } buffer_free(&b); free(sig); +#endif /* !WINDOWS */ + } else { debug("%s: test whether pkalg/pkblob are acceptable for %s %s", __func__, sshkey_type(key), fp); @@ -198,7 +245,11 @@ userauth_pubkey(Authctxt *authctxt) * if a user is not allowed to login. is this an * issue? -markus */ +#ifdef WINDOWS /* key validation in done in agent for Windows */ + { +#else /* !WINDOWS */ if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { +#endif /* !WINDOWS */ packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); @@ -395,6 +446,10 @@ static pid_t subprocess(const char *tag, struct passwd *pw, const char *command, int ac, char **av, FILE **child) { +#ifdef WINDOWS + logit("AuthorizedPrincipalsCommand and AuthorizedKeysCommand are not supported in Windows yet"); + return 0; +#else /* !WINDOWS */ FILE *f; struct stat st; int devnull, p[2], i; @@ -514,6 +569,7 @@ subprocess(const char *tag, struct passwd *pw, const char *command, debug3("%s: %s pid %ld", __func__, tag, (long)pid); *child = f; return pid; +#endif /* !WINDOWS */ } /* Returns 0 if pid exited cleanly, non-zero otherwise */ diff --git a/authfd.c b/authfd.c index a634bcb81..b6ec0ffcd 100644 --- a/authfd.c +++ b/authfd.c @@ -94,6 +94,42 @@ ssh_get_authentication_socket(int *fdp) if (fdp != NULL) *fdp = -1; +#ifdef WINDOWS + /* Auth socket in Windows is a static-named pipe listener in ssh-agent */ + { +#define SSH_AGENT_REG_ROOT L"SOFTWARE\\SSH\\Agent" +#define SSH_AGENT_PIPE_NAME L"\\\\.\\pipe\\ssh-agent" + HKEY agent_root = 0; + DWORD agent_pid = 0, tmp_size = 4, pipe_server_pid = 0xff; + HANDLE h; + RegOpenKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_REG_ROOT, 0, KEY_QUERY_VALUE, &agent_root); + if (agent_root) { + RegQueryValueEx(agent_root, "ProcessId", 0, NULL, (LPBYTE)&agent_pid, &tmp_size); + RegCloseKey(agent_root); + } + + h = CreateFileW(SSH_AGENT_PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (h == INVALID_HANDLE_VALUE) + return SSH_ERR_AGENT_NOT_PRESENT; + + /* + * ensure that connected server pid matches published pid. this provides service side + * auth and prevents mitm + */ + if (!GetNamedPipeServerProcessId(h, &pipe_server_pid) || (agent_pid != pipe_server_pid)) { + debug("agent pid mismatch"); + CloseHandle(h); + return SSH_ERR_AGENT_COMMUNICATION; + } + + /* alloc fd for pipe handle */ + if ((sock = w32_allocate_fd_for_handle(h, FALSE)) < 0) { + CloseHandle(h); + return SSH_ERR_SYSTEM_ERROR; + } + } +#else /* !WINDOWS */ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); if (!authsocket) return SSH_ERR_AGENT_NOT_PRESENT; @@ -113,6 +149,8 @@ ssh_get_authentication_socket(int *fdp) errno = oerrno; return SSH_ERR_SYSTEM_ERROR; } +#endif /* !WINDOWS */ + if (fdp != NULL) *fdp = sock; else @@ -121,7 +159,12 @@ ssh_get_authentication_socket(int *fdp) } /* Communicate with agent: send request and read reply */ +#ifdef WINDOWS +/* for Windows we need to access this function from other places to talk to agent*/ +int +#else /* !WINDOWS */ static int +#endif /* !WINDOWS */ ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) { int r; diff --git a/authfile.c b/authfile.c index 7411b68f6..255907e4e 100644 --- a/authfile.c +++ b/authfile.c @@ -193,6 +193,8 @@ sshkey_perm_ok(int fd, const char *filename) #ifdef HAVE_CYGWIN if (check_ntsec(filename)) #endif + +#ifndef WINDOWS /*TODO - implement permission checks on Windows*/ if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); @@ -203,6 +205,7 @@ sshkey_perm_ok(int fd, const char *filename) error("This private key will be ignored."); return SSH_ERR_KEY_BAD_PERMISSIONS; } +#endif /* !WINDOWS */ return 0; } diff --git a/buffer.c b/buffer.c index c5f708ab2..8734fae26 100644 --- a/buffer.c +++ b/buffer.c @@ -56,6 +56,7 @@ buffer_check_alloc(Buffer *buffer, u_int len) if (ret == SSH_ERR_NO_BUFFER_SPACE) return 0; fatal("%s: %s", __func__, ssh_err(ret)); + return -1; } int @@ -87,6 +88,7 @@ buffer_consume_ret(Buffer *buffer, u_int bytes) if (ret == SSH_ERR_MESSAGE_INCOMPLETE) return -1; fatal("%s: %s", __func__, ssh_err(ret)); + return -1; } void @@ -106,6 +108,7 @@ buffer_consume_end_ret(Buffer *buffer, u_int bytes) if (ret == SSH_ERR_MESSAGE_INCOMPLETE) return -1; fatal("%s: %s", __func__, ssh_err(ret)); + return -1; } void diff --git a/channels.c b/channels.c index bef8ad6aa..ef4018b0e 100644 --- a/channels.c +++ b/channels.c @@ -2050,6 +2050,7 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) return; } +#ifndef WINDOWS /*TODO - implement user check for Windows*/ if (getpeereid(newsock, &euid, &egid) < 0) { error("%s getpeereid failed: %s", __func__, strerror(errno)); @@ -2062,6 +2063,7 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) close(newsock); return; } +#endif /* !WINDOWS */ nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, 0, "mux-control", 1); diff --git a/clientloop.c b/clientloop.c index 4289a4081..5bec8c0f4 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1219,6 +1219,9 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, continue; case '&': +#ifdef WINDOWS + fatal("Background execution is not supported in Windows"); +#else /* !WINDOWS */ if (c && c->ctl_chan != -1) goto noescape; /* @@ -1269,6 +1272,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, } } continue; +#endif /* !WINDOWS */ case '?': print_escape_help(berr, escape_char, compat20, diff --git a/contrib/win32/openssh/README.txt b/contrib/win32/openssh/README.txt new file mode 100644 index 000000000..97ebd10a4 --- /dev/null +++ b/contrib/win32/openssh/README.txt @@ -0,0 +1,22 @@ +Custom paths for the visual studio projects are defined in paths.targets. + +All projects import this targets file, and it should be in the same directory as the project. + +The custom paths are: + +OpenSSH-Src-Path = The directory path of the OpenSSH root source directory (with trailing slash) +OpenSSH-Bin-Path = The directory path of the location to which binaries are placed. This is the output of the binary projects +OpenSSH-Lib-Path = The directory path of the location to which libraries are placed. This is the output of the libary projects +OpenSSL-Win32-Release-Path = The directory path of OpenSSL statically linked compiled for Win32-Release. This path is used for + include and library paths and for Win32-Release. +OpenSSL-Win32-Debug-Path = The directory path of OpenSSL statically linked compiled for Win32-Debug. This path is used for + include and library paths and for Win32-Debug. +OpenSSL-x64-Release-Path = The directory path of OpenSSL statically linked compiled for x64-Release. This path is used for + include and library paths and for x64-Release. +OpenSSL-x64-Debug-Path = The directory path of OpenSSL statically linked compiled for x64-Debug. This path is used for + include and library paths and for x64-Debug. + + + +The Release/Debug OpenSSL directories output is the standard 'install' output of OpenSSL compiled under Visual Studio 2015 using static c-runtimes. + diff --git a/contrib/win32/openssh/VSWithBuildTools.xml b/contrib/win32/openssh/VSWithBuildTools.xml new file mode 100644 index 000000000..279fedf85 --- /dev/null +++ b/contrib/win32/openssh/VSWithBuildTools.xml @@ -0,0 +1,84 @@ + + + + + + + diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln new file mode 100644 index 000000000..ee8c928b7 --- /dev/null +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -0,0 +1,343 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh", "ssh.vcxproj", "{74E69D5E-A1EF-46EA-9173-19A412774104}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libssh", "libssh.vcxproj", "{05E1115F-8529-46D0-AAAF-52A404CE79A7}" + ProjectSection(ProjectDependencies) = postProject + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openbsd_compat", "openbsd_compat.vcxproj", "{DD483F7D-C553-4740-BC1A-903805AD0174}" + ProjectSection(ProjectDependencies) = postProject + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-keygen", "keygen.vcxproj", "{47496135-131B-41D6-BF2B-EE7144873DD0}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sftp", "sftp.vcxproj", "{BBEFF9D7-0BC3-41D1-908B-8052158B5052}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sftp-server", "sftp-server.vcxproj", "{6657614F-7821-4D55-96EF-7C3C4B551880}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sshd", "sshd.vcxproj", "{F58FF6BA-098B-4DB9-9609-A030DFB4D03F}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "config", "config.vcxproj", "{8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-lsa", "ssh-lsa.vcxproj", "{02FB3D98-6516-42C6-9762-98811A99960F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "posix_compat", "win32iocompat.vcxproj", "{0D02F0F0-013B-4EE3-906D-86517F3822C0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-shellhost", "ssh-shellhost.vcxproj", "{C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-agent", "ssh-agent.vcxproj", "{F6644EC5-D6B6-42A1-828C-75E2977470E0}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-add", "ssh-add.vcxproj", "{029797FF-C986-43DE-95CD-2E771E86AEBC}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scp", "scp.vcxproj", "{29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-bitmap", "unittest-bitmap.vcxproj", "{D901596E-76C7-4608-9CFA-2B42A9FD7250}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-kex", "unittest-kex.vcxproj", "{8EC56B06-5A9A-4D6D-804D-037FE26FD43E}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-sshbuf", "unittest-sshbuf.vcxproj", "{CD9740CE-C96E-49B3-823F-012E09D17806}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-win32compat", "unittest-win32compat.vcxproj", "{BF295BA9-4BF8-43F8-8CBF-FAE84815466C}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-utf8", "unittest-utf8.vcxproj", "{114CAA59-46C0-4B87-BA86-C1946A68101D}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-hostkeys", "unittest-hostkeys.vcxproj", "{890C6129-286F-4CD8-8252-FB8D3B4E6E1B}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest-sshkey", "unittest-sshkey.vcxproj", "{FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}" + ProjectSection(ProjectDependencies) = postProject + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {0D02F0F0-013B-4EE3-906D-86517F3822C0} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{17322AAF-808F-4646-AD37-5B0EDDCB8F3E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A8096E32-E084-4FA0-AE01-A8D909EB2BB4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {74E69D5E-A1EF-46EA-9173-19A412774104}.Debug|x64.ActiveCfg = Debug|x64 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Debug|x64.Build.0 = Debug|x64 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Debug|x86.ActiveCfg = Debug|Win32 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Debug|x86.Build.0 = Debug|Win32 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Release|x64.ActiveCfg = Release|x64 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Release|x64.Build.0 = Release|x64 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Release|x86.ActiveCfg = Release|Win32 + {74E69D5E-A1EF-46EA-9173-19A412774104}.Release|x86.Build.0 = Release|Win32 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Debug|x64.ActiveCfg = Debug|x64 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Debug|x64.Build.0 = Debug|x64 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Debug|x86.ActiveCfg = Debug|Win32 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Debug|x86.Build.0 = Debug|Win32 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Release|x64.ActiveCfg = Release|x64 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Release|x64.Build.0 = Release|x64 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Release|x86.ActiveCfg = Release|Win32 + {05E1115F-8529-46D0-AAAF-52A404CE79A7}.Release|x86.Build.0 = Release|Win32 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Debug|x64.ActiveCfg = Debug|x64 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Debug|x64.Build.0 = Debug|x64 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Debug|x86.ActiveCfg = Debug|Win32 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Debug|x86.Build.0 = Debug|Win32 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Release|x64.ActiveCfg = Release|x64 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Release|x64.Build.0 = Release|x64 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Release|x86.ActiveCfg = Release|Win32 + {DD483F7D-C553-4740-BC1A-903805AD0174}.Release|x86.Build.0 = Release|Win32 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Debug|x64.ActiveCfg = Debug|x64 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Debug|x64.Build.0 = Debug|x64 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Debug|x86.ActiveCfg = Debug|Win32 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Debug|x86.Build.0 = Debug|Win32 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Release|x64.ActiveCfg = Release|x64 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Release|x64.Build.0 = Release|x64 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Release|x86.ActiveCfg = Release|Win32 + {47496135-131B-41D6-BF2B-EE7144873DD0}.Release|x86.Build.0 = Release|Win32 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Debug|x64.ActiveCfg = Debug|x64 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Debug|x64.Build.0 = Debug|x64 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Debug|x86.ActiveCfg = Debug|Win32 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Debug|x86.Build.0 = Debug|Win32 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Release|x64.ActiveCfg = Release|x64 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Release|x64.Build.0 = Release|x64 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Release|x86.ActiveCfg = Release|Win32 + {BBEFF9D7-0BC3-41D1-908B-8052158B5052}.Release|x86.Build.0 = Release|Win32 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Debug|x64.ActiveCfg = Debug|x64 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Debug|x64.Build.0 = Debug|x64 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Debug|x86.ActiveCfg = Debug|Win32 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Debug|x86.Build.0 = Debug|Win32 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Release|x64.ActiveCfg = Release|x64 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Release|x64.Build.0 = Release|x64 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Release|x86.ActiveCfg = Release|Win32 + {6657614F-7821-4D55-96EF-7C3C4B551880}.Release|x86.Build.0 = Release|Win32 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Debug|x64.ActiveCfg = Debug|x64 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Debug|x64.Build.0 = Debug|x64 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Debug|x86.ActiveCfg = Debug|Win32 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Debug|x86.Build.0 = Debug|Win32 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Release|x64.ActiveCfg = Release|x64 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Release|x64.Build.0 = Release|x64 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Release|x86.ActiveCfg = Release|Win32 + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F}.Release|x86.Build.0 = Release|Win32 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Debug|x64.ActiveCfg = Debug|x64 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Debug|x64.Build.0 = Debug|x64 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Debug|x86.ActiveCfg = Debug|Win32 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Debug|x86.Build.0 = Debug|Win32 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Release|x64.ActiveCfg = Release|x64 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Release|x64.Build.0 = Release|x64 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Release|x86.ActiveCfg = Release|Win32 + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}.Release|x86.Build.0 = Release|Win32 + {02FB3D98-6516-42C6-9762-98811A99960F}.Debug|x64.ActiveCfg = Debug|x64 + {02FB3D98-6516-42C6-9762-98811A99960F}.Debug|x64.Build.0 = Debug|x64 + {02FB3D98-6516-42C6-9762-98811A99960F}.Debug|x86.ActiveCfg = Debug|Win32 + {02FB3D98-6516-42C6-9762-98811A99960F}.Debug|x86.Build.0 = Debug|Win32 + {02FB3D98-6516-42C6-9762-98811A99960F}.Release|x64.ActiveCfg = Release|x64 + {02FB3D98-6516-42C6-9762-98811A99960F}.Release|x64.Build.0 = Release|x64 + {02FB3D98-6516-42C6-9762-98811A99960F}.Release|x86.ActiveCfg = Release|Win32 + {02FB3D98-6516-42C6-9762-98811A99960F}.Release|x86.Build.0 = Release|Win32 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Debug|x64.ActiveCfg = Debug|x64 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Debug|x64.Build.0 = Debug|x64 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Debug|x86.ActiveCfg = Debug|Win32 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Debug|x86.Build.0 = Debug|Win32 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Release|x64.ActiveCfg = Release|x64 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Release|x64.Build.0 = Release|x64 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Release|x86.ActiveCfg = Release|Win32 + {0D02F0F0-013B-4EE3-906D-86517F3822C0}.Release|x86.Build.0 = Release|Win32 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Debug|x64.ActiveCfg = Debug|x64 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Debug|x64.Build.0 = Debug|x64 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Debug|x86.ActiveCfg = Debug|Win32 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Debug|x86.Build.0 = Debug|Win32 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Release|x64.ActiveCfg = Release|x64 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Release|x64.Build.0 = Release|x64 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Release|x86.ActiveCfg = Release|Win32 + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}.Release|x86.Build.0 = Release|Win32 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Debug|x64.ActiveCfg = Debug|x64 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Debug|x64.Build.0 = Debug|x64 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Debug|x86.ActiveCfg = Debug|Win32 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Debug|x86.Build.0 = Debug|Win32 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Release|x64.ActiveCfg = Release|x64 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Release|x64.Build.0 = Release|x64 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Release|x86.ActiveCfg = Release|Win32 + {F6644EC5-D6B6-42A1-828C-75E2977470E0}.Release|x86.Build.0 = Release|Win32 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Debug|x64.ActiveCfg = Debug|x64 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Debug|x64.Build.0 = Debug|x64 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Debug|x86.ActiveCfg = Debug|Win32 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Debug|x86.Build.0 = Debug|Win32 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Release|x64.ActiveCfg = Release|x64 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Release|x64.Build.0 = Release|x64 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Release|x86.ActiveCfg = Release|Win32 + {029797FF-C986-43DE-95CD-2E771E86AEBC}.Release|x86.Build.0 = Release|Win32 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Debug|x64.ActiveCfg = Debug|x64 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Debug|x64.Build.0 = Debug|x64 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Debug|x86.ActiveCfg = Debug|Win32 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Debug|x86.Build.0 = Debug|Win32 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Release|x64.ActiveCfg = Release|x64 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Release|x64.Build.0 = Release|x64 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Release|x86.ActiveCfg = Release|Win32 + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}.Release|x86.Build.0 = Release|Win32 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Debug|x64.ActiveCfg = Debug|x64 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Debug|x64.Build.0 = Debug|x64 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Debug|x86.ActiveCfg = Debug|Win32 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Debug|x86.Build.0 = Debug|Win32 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Release|x64.ActiveCfg = Release|x64 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Release|x64.Build.0 = Release|x64 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Release|x86.ActiveCfg = Release|Win32 + {D901596E-76C7-4608-9CFA-2B42A9FD7250}.Release|x86.Build.0 = Release|Win32 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Debug|x64.ActiveCfg = Debug|x64 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Debug|x64.Build.0 = Debug|x64 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Debug|x86.ActiveCfg = Debug|Win32 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Debug|x86.Build.0 = Debug|Win32 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Release|x64.ActiveCfg = Release|x64 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Release|x64.Build.0 = Release|x64 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Release|x86.ActiveCfg = Release|Win32 + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E}.Release|x86.Build.0 = Release|Win32 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Debug|x64.ActiveCfg = Debug|x64 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Debug|x64.Build.0 = Debug|x64 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Debug|x86.ActiveCfg = Debug|Win32 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Debug|x86.Build.0 = Debug|Win32 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Release|x64.ActiveCfg = Release|x64 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Release|x64.Build.0 = Release|x64 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Release|x86.ActiveCfg = Release|Win32 + {CD9740CE-C96E-49B3-823F-012E09D17806}.Release|x86.Build.0 = Release|Win32 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Debug|x64.ActiveCfg = Debug|x64 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Debug|x64.Build.0 = Debug|x64 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Debug|x86.ActiveCfg = Debug|Win32 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Debug|x86.Build.0 = Debug|Win32 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x64.ActiveCfg = Release|x64 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x64.Build.0 = Release|x64 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x86.ActiveCfg = Release|Win32 + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C}.Release|x86.Build.0 = Release|Win32 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x64.ActiveCfg = Debug|x64 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x64.Build.0 = Debug|x64 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x86.ActiveCfg = Debug|Win32 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Debug|x86.Build.0 = Debug|Win32 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x64.ActiveCfg = Release|x64 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x64.Build.0 = Release|x64 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x86.ActiveCfg = Release|Win32 + {114CAA59-46C0-4B87-BA86-C1946A68101D}.Release|x86.Build.0 = Release|Win32 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x64.ActiveCfg = Debug|x64 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x64.Build.0 = Debug|x64 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x86.ActiveCfg = Debug|Win32 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Debug|x86.Build.0 = Debug|Win32 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Release|x64.ActiveCfg = Release|x64 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Release|x64.Build.0 = Release|x64 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Release|x86.ActiveCfg = Release|Win32 + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B}.Release|x86.Build.0 = Release|Win32 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Debug|x64.ActiveCfg = Debug|x64 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Debug|x64.Build.0 = Debug|x64 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Debug|x86.ActiveCfg = Debug|Win32 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Debug|x86.Build.0 = Debug|Win32 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Release|x64.ActiveCfg = Release|x64 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Release|x64.Build.0 = Release|x64 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Release|x86.ActiveCfg = Release|Win32 + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {74E69D5E-A1EF-46EA-9173-19A412774104} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {05E1115F-8529-46D0-AAAF-52A404CE79A7} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {47496135-131B-41D6-BF2B-EE7144873DD0} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {BBEFF9D7-0BC3-41D1-908B-8052158B5052} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {6657614F-7821-4D55-96EF-7C3C4B551880} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {02FB3D98-6516-42C6-9762-98811A99960F} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {0D02F0F0-013B-4EE3-906D-86517F3822C0} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {F6644EC5-D6B6-42A1-828C-75E2977470E0} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {029797FF-C986-43DE-95CD-2E771E86AEBC} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24} = {17322AAF-808F-4646-AD37-5B0EDDCB8F3E} + {D901596E-76C7-4608-9CFA-2B42A9FD7250} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {8EC56B06-5A9A-4D6D-804D-037FE26FD43E} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {CD9740CE-C96E-49B3-823F-012E09D17806} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {BF295BA9-4BF8-43F8-8CBF-FAE84815466C} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {114CAA59-46C0-4B87-BA86-C1946A68101D} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {890C6129-286F-4CD8-8252-FB8D3B4E6E1B} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + {FC568FF0-60F2-4B2E-AF62-FD392EDBA1B9} = {A8096E32-E084-4FA0-AE01-A8D909EB2BB4} + EndGlobalSection +EndGlobal diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs new file mode 100644 index 000000000..e798289b2 --- /dev/null +++ b/contrib/win32/openssh/config.h.vs @@ -0,0 +1,1715 @@ +#pragma once + +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define if you have a getaddrinfo that fails + for the all-zeros IPv6 address + */ +/* #undef AIX_GETNAMEINFO_HACK */ + +/* Define if your AIX loginfailed() function + takes 4 arguments (AIX >= 5.2) + */ +/* #undef AIX_LOGINFAILED_4ARG */ + +/* System only supports IPv4 audit records */ +/* #undef AU_IPv4 */ + +/* Define if your resolver libs need this for getrrsetbyname */ +/* #undef BIND_8_COMPAT */ + +/* Define if cmsg_type is not passed correctly */ +/* #undef BROKEN_CMSG_TYPE */ + +/* getaddrinfo is broken (if present) */ +/* #undef BROKEN_GETADDRINFO */ + +/* getgroups(0,NULL) will return -1 */ +/* #undef BROKEN_GETGROUPS */ + +/* FreeBSD glob does not do what we need */ +/* #undef BROKEN_GLOB */ + +/* Define if you system's inet_ntoa is busted + (e.g. Irix gcc issue) */ +/* #undef BROKEN_INET_NTOA */ + +/* ia_uinfo routines not supported by OS yet */ +/* #undef BROKEN_LIBIAF */ + +/* Ultrix mmap can't map files */ +/* #undef BROKEN_MMAP */ + +/* Define if your struct dirent expects you to + allocate extra space for + d_name */ +/* #undef BROKEN_ONE_BYTE_DIRENT_D_NAME */ + +/* Can't do comparisons on readv */ +/* #undef BROKEN_READV_COMPARISON */ + +/* Define if you have a broken realpath. */ +/* #undef BROKEN_REALPATH */ + +/* Needed for NeXT */ +/* #undef BROKEN_SAVED_UIDS */ + +/* Define if your setregid() is broken */ +/* #undef BROKEN_SETREGID */ + +/* Define if your setresgid() is broken */ +/* #undef BROKEN_SETRESGID */ + +/* Define if your setresuid() is broken */ +/* #undef BROKEN_SETRESUID */ + +/* Define if your setreuid() is broken */ +/* #undef BROKEN_SETREUID */ + +/* LynxOS has broken setvbuf() implementation */ +/* #undef BROKEN_SETVBUF */ + +/* QNX shadow support is broken */ +/* #undef BROKEN_SHADOW_EXPIRE */ + +/* Define if your snprintf is busted */ +/* #undef BROKEN_SNPRINTF */ + +/* tcgetattr with ICANON may hang */ +#define BROKEN_TCGETATTR_ICANON 1 + +/* updwtmpx is broken (if present) */ +/* #undef BROKEN_UPDWTMPX */ + +/* Define if you have BSD auth support */ +/* #undef BSD_AUTH */ + +/* Define if you want to specify the path to your lastlog file */ +#define CONF_LASTLOG_FILE "/var/log/lastlog" + +/* Define if you want to specify the path to your utmp file */ +#define CONF_UTMP_FILE "/var/run/utmp" + +/* Define if you want to specify the path to your wtmpx file */ +/* #undef CONF_WTMPX_FILE */ + +/* Define if you want to specify the path to your wtmp file */ +/* #undef CONF_WTMP_FILE */ + +/* Define if your platform needs to skip post auth + file descriptor passing */ +#define DISABLE_FD_PASSING 1 + +/* Define if you don't want to use lastlog */ +/* #undef DISABLE_LASTLOG */ + +/* Define if you don't want to use your + system's login() call */ +/* #undef DISABLE_LOGIN */ + +/* Define if you don't want to use pututline() + etc. to write [uw]tmp */ +/* #undef DISABLE_PUTUTLINE */ + +/* Define if you don't want to use pututxline() + etc. to write [uw]tmpx */ +/* #undef DISABLE_PUTUTXLINE */ + +/* Define if you want to disable shadow passwords */ +#define DISABLE_SHADOW 1 + +/* Define if you don't want to use utmp */ +#define DISABLE_UTMP 1 + +/* Define if you don't want to use utmpx */ +#define DISABLE_UTMPX 1 + +/* Define if you don't want to use wtmp */ +#define DISABLE_WTMP 1 + +/* Define if you don't want to use wtmpx */ +#define DISABLE_WTMPX 1 + +/* Enable for PKCS#11 support */ +/* #undef ENABLE_PKCS11 */ + +/* File names may not contain backslash characters */ +/* #undef FILESYSTEM_NO_BACKSLASH */ + +/* fsid_t has member val */ +/* #undef FSID_HAS_VAL */ + +/* fsid_t has member __val */ +/* #undef FSID_HAS___VAL */ + +/* Define to 1 if the `getpgrp' function requires zero arguments. */ +/* #undef GETPGRP_VOID */ + +/* Conflicting defs for getspnam */ +/* #undef GETSPNAM_CONFLICTING_DEFS */ + +/* Define if your system glob() function has + the GLOB_ALTDIRFUNC extension */ +/* #undef GLOB_HAS_ALTDIRFUNC */ + +/* Define if your system glob() function has + gl_matchc options in glob_t */ +#define GLOB_HAS_GL_MATCHC 1 + +/* Define if your system glob() function has + gl_statv options in glob_t */ +#define GLOB_HAS_GL_STATV 1 + +/* Define this if you want GSSAPI + support in the version 2 protocol */ +/* #undef GSSAPI */ + +/* Define if you want to use shadow password expire field */ +/* #undef HAS_SHADOW_EXPIRE */ + +/* Define if your system uses access rights style + file descriptor passing */ +/* #undef HAVE_ACCRIGHTS_IN_MSGHDR */ + +/* Define if you have ut_addr in utmp.h */ +/* #undef HAVE_ADDR_IN_UTMP */ + +/* Define if you have ut_addr in utmpx.h */ +/* #undef HAVE_ADDR_IN_UTMPX */ + +/* Define if you have ut_addr_v6 in utmp.h */ +/* #undef HAVE_ADDR_V6_IN_UTMP */ + +/* Define if you have ut_addr_v6 in utmpx.h */ +/* #undef HAVE_ADDR_V6_IN_UTMPX */ + +/* Define to 1 if you have the `arc4random' function. */ +/* #undef HAVE_ARC4RANDOM */ + +/* Define to 1 if you have the `arc4random_buf' function. */ +/* #undef HAVE_ARC4RANDOM_BUF */ + +/* Define to 1 if you have the `arc4random_uniform' function. */ +/* #undef HAVE_ARC4RANDOM_UNIFORM */ + +/* Define to 1 if you have the `asprintf' function. */ +/* #undef HAVE_ASPRINTF */ + +/* OpenBSD's gcc has bounded */ +/* #undef HAVE_ATTRIBUTE__BOUNDED__ */ + +/* Have attribute nonnull */ +#define HAVE_ATTRIBUTE__NONNULL__ 1 + +/* OpenBSD's gcc has sentinel */ +/* #undef HAVE_ATTRIBUTE__SENTINEL__ */ + +/* Define to 1 if you have the `aug_get_machine' function. */ +/* #undef HAVE_AUG_GET_MACHINE */ + +/* Define to 1 if you have the `b64_ntop' function. */ +/* #undef HAVE_B64_NTOP */ + +/* Define to 1 if you have the `b64_pton' function. */ +/* #undef HAVE_B64_PTON */ + +/* Define if you have the basename function. */ +#define HAVE_BASENAME 1 + +/* Define to 1 if you have the `bcopy' function. */ +/* #undef HAVE_BCOPY */ + +/* Define to 1 if you have the `bindresvport_sa' function. */ +/* #undef HAVE_BINDRESVPORT_SA */ + +/* Define to 1 if you have the `BN_is_prime_ex' function. */ +#define HAVE_BN_IS_PRIME_EX 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BSM_AUDIT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BSTRING_H */ + +/* Define to 1 if you have the `clock' function. */ +#define HAVE_CLOCK 1 + +/* define if you have clock_t data type */ +#define HAVE_CLOCK_T 1 + +/* Define to 1 if you have the `closefrom' function. */ +/* #undef HAVE_CLOSEFROM */ + +/* Define if gai_strerror() returns const char * */ +/* #undef HAVE_CONST_GAI_STRERROR_PROTO */ + +/* Define if your system uses ancillary data style + file descriptor passing */ +/* #undef HAVE_CONTROL_IN_MSGHDR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CRYPTO_SHA2_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CRYPT_H */ + +/* Define if you are on Cygwin */ +/* #undef HAVE_CYGWIN */ + +/* Define if your libraries define daemon() */ +/* #undef HAVE_DAEMON */ + +/* Define to 1 if you have the declaration of `authenticate', and to 0 if you + don't. */ +/* #undef HAVE_DECL_AUTHENTICATE */ + +/* Define to 1 if you have the declaration of `GLOB_NOMATCH', and to 0 if you + don't. */ +#define HAVE_DECL_GLOB_NOMATCH 1 + +/* Define to 1 if you have the declaration of `h_errno', and to 0 if you + don't. */ +#define HAVE_DECL_H_ERRNO 0 + +/* Define to 1 if you have the declaration of `loginfailed', and to 0 if you + don't. */ +/* #undef HAVE_DECL_LOGINFAILED */ + +/* Define to 1 if you have the declaration of `loginrestrictions', and to 0 if + you don't. */ +/* #undef HAVE_DECL_LOGINRESTRICTIONS */ + +/* Define to 1 if you have the declaration of `loginsuccess', and to 0 if you + don't. */ +/* #undef HAVE_DECL_LOGINSUCCESS */ + +/* Define to 1 if you have the declaration of `MAXSYMLINKS', and to 0 if you + don't. */ +#define HAVE_DECL_MAXSYMLINKS 0 + +/* Define to 1 if you have the declaration of `offsetof', and to 0 if you + don't. */ +#define HAVE_DECL_OFFSETOF 1 + +/* Define to 1 if you have the declaration of `O_NONBLOCK', and to 0 if you + don't. */ +#define HAVE_DECL_O_NONBLOCK 0 + +/* Define to 1 if you have the declaration of `passwdexpired', and to 0 if you + don't. */ +/* #undef HAVE_DECL_PASSWDEXPIRED */ + +/* Define to 1 if you have the declaration of `setauthdb', and to 0 if you + don't. */ +/* #undef HAVE_DECL_SETAUTHDB */ + +/* Define to 1 if you have the declaration of `SHUT_RD', and to 0 if you + don't. */ +#define HAVE_DECL_SHUT_RD 1 + +/* Define to 1 if you have the declaration of `writev', and to 0 if you don't. + */ +#define HAVE_DECL_WRITEV 0 + +/* Define to 1 if you have the declaration of `_getlong', and to 0 if you + don't. */ +/* #undef HAVE_DECL__GETLONG */ + +/* Define to 1 if you have the declaration of `_getshort', and to 0 if you + don't. */ +/* #undef HAVE_DECL__GETSHORT */ + +/* Define if you have /dev/ptmx */ +#define HAVE_DEV_PTMX 1 + +/* Define if you have /dev/ptc */ +/* #undef HAVE_DEV_PTS_AND_PTC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DIRENT_H + +/* Define to 1 if you have the `dirfd' function. */ +/* #undef HAVE_DIRFD */ + +/* Define to 1 if you have the `dirname' function. */ +/* #define HAVE_DIRNAME 1 */ + +/* Define to 1 if you have the `DSA_generate_parameters_ex' function. */ +#define HAVE_DSA_GENERATE_PARAMETERS_EX 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define to 1 if you have the `endutent' function. */ +/* #undef HAVE_ENDUTENT */ + +/* Define to 1 if you have the `endutxent' function. */ +/* #undef HAVE_ENDUTXENT */ + +/* Define if your system has /etc/default/login */ +/* #undef HAVE_ETC_DEFAULT_LOGIN */ + +/* Define to 1 if you have the `EVP_sha256' function. */ +#define HAVE_EVP_SHA256 1 + +/* Define if you have ut_exit in utmp.h */ +/* #undef HAVE_EXIT_IN_UTMP */ + +/* Define to 1 if you have the `fchmod' function. */ +/* #undef HAVE_FCHMOD */ + +/* Define to 1 if you have the `fchown' function. */ +/* #undef HAVE_FCHOWN */ + +/* Use F_CLOSEM fcntl for closefrom */ +/* #undef HAVE_FCNTL_CLOSEM */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FEATURES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FLOATINGPOINT_H */ + +/* Define to 1 if you have the `fmt_scaled' function. */ +/* #undef HAVE_FMT_SCALED */ + +/* Define to 1 if you have the `freeaddrinfo' function. */ +/* #undef HAVE_FREEADDRINFO */ + +/* Define to 1 if the system has the type `fsblkcnt_t'. */ +/* #undef HAVE_FSBLKCNT_T */ + +/* Define to 1 if the system has the type `fsfilcnt_t'. */ +/* #undef HAVE_FSFILCNT_T */ + +/* Define to 1 if you have the `fstatvfs' function. */ +#define HAVE_FSTATVFS 1 + +/* Define to 1 if you have the `futimes' function. */ +/* #undef HAVE_FUTIMES */ + +/* Define to 1 if you have the `gai_strerror' function. */ +/* #undef HAVE_GAI_STRERROR */ + +/* Define to 1 if you have the `getaddrinfo' function. */ +/* #undef HAVE_GETADDRINFO */ + +/* Define to 1 if you have the `getaudit' function. */ +/* #undef HAVE_GETAUDIT */ + +/* Define to 1 if you have the `getaudit_addr' function. */ +/* #undef HAVE_GETAUDIT_ADDR */ + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgrouplist' function. */ +/* #undef HAVE_GETGROUPLIST */ + +/* Define to 1 if you have the `getgrset' function. */ +/* #undef HAVE_GETGRSET */ + +/* Define to 1 if you have the `getlastlogxbyname' function. */ +/* #undef HAVE_GETLASTLOGXBYNAME */ + +/* Define to 1 if you have the `getluid' function. */ +/* #undef HAVE_GETLUID */ + +/* Define to 1 if you have the `getnameinfo' function. */ +/* #undef HAVE_GETNAMEINFO */ + +/* Define to 1 if you have the `getopt' function. */ +#define HAVE_GETOPT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define if your getopt(3) defines and uses optreset */ +/* #undef HAVE_GETOPT_OPTRESET */ + +/* Define if your libraries define getpagesize() */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getpeereid' function. */ +/* #undef HAVE_GETPEEREID */ + +/* Define to 1 if you have the `getpeerucred' function. */ +/* #undef HAVE_GETPEERUCRED */ + +/* Define to 1 if you have the `getpwanam' function. */ +/* #undef HAVE_GETPWANAM */ + +/* Define to 1 if you have the `getrlimit' function. */ +/* #undef HAVE_GETRLIMIT */ + +/* Define if getrrsetbyname() exists */ +/* #undef HAVE_GETRRSETBYNAME */ + +/* Define to 1 if you have the `getrusage' function. */ +/* #undef HAVE_GETRUSAGE */ + +/* Define to 1 if you have the `getseuserbyname' function. */ +/* #undef HAVE_GETSEUSERBYNAME */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getttyent' function. */ +/* #undef HAVE_GETTTYENT */ + +/* Define to 1 if you have the `getutent' function. */ +/* #undef HAVE_GETUTENT */ + +/* Define to 1 if you have the `getutid' function. */ +/* #undef HAVE_GETUTID */ + +/* Define to 1 if you have the `getutline' function. */ +/* #undef HAVE_GETUTLINE */ + +/* Define to 1 if you have the `getutxent' function. */ +/* #undef HAVE_GETUTXENT */ + +/* Define to 1 if you have the `getutxid' function. */ +/* #undef HAVE_GETUTXID */ + +/* Define to 1 if you have the `getutxline' function. */ +/* #undef HAVE_GETUTXLINE */ + +/* Define to 1 if you have the `getutxuser' function. */ +/* #undef HAVE_GETUTXUSER */ + +/* Define to 1 if you have the `get_default_context_with_level' function. */ +/* #undef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL */ + +/* Define to 1 if you have the `glob' function. */ +/* #undef HAVE_GLOB */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GLOB_H 1 + +/* Define to 1 if you have the `group_from_gid' function. */ +/* #undef HAVE_GROUP_FROM_GID */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GSSAPI_GENERIC_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GSSAPI_GSSAPI_GENERIC_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GSSAPI_GSSAPI_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_GSSAPI_GSSAPI_KRB5_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GSSAPI_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GSSAPI_KRB5_H */ + +/* Define if HEADER.ad exists in arpa/nameser.h */ +/* #undef HAVE_HEADER_AD */ + +/* Define if you have ut_host in utmp.h */ +/* #undef HAVE_HOST_IN_UTMP */ + +/* Define if you have ut_host in utmpx.h */ +/* #undef HAVE_HOST_IN_UTMPX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IAF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IA_H */ + +/* Define if you have ut_id in utmp.h */ +/* #undef HAVE_ID_IN_UTMP */ + +/* Define if you have ut_id in utmpx.h */ +/* #undef HAVE_ID_IN_UTMPX */ + +/* Define to 1 if you have the `inet_aton' function. */ +/* #undef HAVE_INET_ATON */ + +/* Define to 1 if you have the `inet_ntoa' function. */ +/* #undef HAVE_INET_NTOA */ + +/* Define to 1 if you have the `inet_ntop' function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have the `innetgr' function. */ +/* #undef HAVE_INNETGR */ + +/* define if you have int64_t data type */ +#define HAVE_INT64_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* define if you have intxx_t data type */ +#define HAVE_INTXX_T 1 + +/* Define to 1 if the system has the type `in_addr_t'. */ +/* #undef HAVE_IN_ADDR_T */ + +/* Define to 1 if the system has the type `in_port_t'. */ +/* #undef HAVE_IN_PORT_T */ + +/* Define if you have isblank(3C). */ +#define HAVE_ISBLANK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LASTLOG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBAUDIT_H */ + +/* Define to 1 if you have the `bsm' library (-lbsm). */ +/* #undef HAVE_LIBBSM */ + +/* Define to 1 if you have the `crypt' library (-lcrypt). */ +/* #undef HAVE_LIBCRYPT */ + +/* Define to 1 if you have the `dl' library (-ldl). */ +/* #undef HAVE_LIBDL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define if system has libiaf that supports set_id */ +/* #undef HAVE_LIBIAF */ + +/* Define to 1 if you have the `network' library (-lnetwork). */ +/* #undef HAVE_LIBNETWORK */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `pam' library (-lpam). */ +/* #undef HAVE_LIBPAM */ + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define to 1 if you have the `xnet' library (-lxnet). */ +/* #undef HAVE_LIBXNET */ + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_IF_TUN_H */ + +/* Define if your libraries define login() */ +/* #undef HAVE_LOGIN */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LOGIN_CAP_H */ + +/* Define to 1 if you have the `login_getcapbool' function. */ +/* #undef HAVE_LOGIN_GETCAPBOOL */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LOGIN_H */ + +/* Define to 1 if you have the `logout' function. */ +/* #undef HAVE_LOGOUT */ + +/* Define to 1 if you have the `logwtmp' function. */ +/* #undef HAVE_LOGWTMP */ + +/* Define to 1 if the system has the type `long double'. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define to 1 if the system has the type `long long'. */ +#define HAVE_LONG_LONG 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MAILLOCK_H */ + +/* Define to 1 if you have the `md5_crypt' function. */ +/* #undef HAVE_MD5_CRYPT */ + +/* Define if you want to allow MD5 passwords */ +/* #undef HAVE_MD5_PASSWORDS */ + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkdtemp' function. */ +/* #undef HAVE_MKDTEMP */ + +/* Define to 1 if you have the `mmap' function. */ +/* #undef HAVE_MMAP */ + +/* define if you have mode_t data type */ +#define HAVE_MODE_T 1 + +/* Some systems put nanosleep outside of libc */ +/* #undef HAVE_NANOSLEEP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETDB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETGROUP_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NET_IF_TUN_H */ + +/* Define if you are on NeXT */ +/* #undef HAVE_NEXT */ + +/* Define to 1 if you have the `ngetaddrinfo' function. */ +/* #undef HAVE_NGETADDRINFO */ + +/* Define to 1 if you have the `nsleep' function. */ +/* #undef HAVE_NSLEEP */ + +/* Define to 1 if you have the `ogetaddrinfo' function. */ +/* #undef HAVE_OGETADDRINFO */ + +/* Define if you have an old version of PAM + which takes only one argument to + pam_strerror */ +/* #undef HAVE_OLD_PAM */ + +/* Define to 1 if you have the `openlog_r' function. */ +/* #undef HAVE_OPENLOG_R */ + +/* Define to 1 if you have the `openpty' function. */ +/* #undef HAVE_OPENPTY */ + +/* Define if your ssl headers are included + with #include + */ +#define HAVE_OPENSSL 1 + +/* Define if you have Digital Unix Security + Integration Architecture */ +/* #undef HAVE_OSF_SIA */ + +/* Define to 1 if you have the `pam_getenvlist' function. */ +/* #undef HAVE_PAM_GETENVLIST */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PAM_PAM_APPL_H */ + +/* Define to 1 if you have the `pam_putenv' function. */ +/* #undef HAVE_PAM_PUTENV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PATHS_H */ + +/* Define if you have ut_pid in utmp.h */ +/* #undef HAVE_PID_IN_UTMP */ + +/* define if you have pid_t data type */ +#define HAVE_PID_T 1 + +/* Define to 1 if you have the `poll' function. */ +/* #undef HAVE_POLL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the `prctl' function. */ +/* #undef HAVE_PRCTL */ + +/* Define to 1 if you have priveleged-port concept */ +/* #undef HAVE_PRIV_CONCEPT */ + +/* Define if you have /proc/$pid/fd */ +#define HAVE_PROC_PID 1 + +/* Define to 1 if you have the `pstat' function. */ +/* #undef HAVE_PSTAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTY_H */ + +/* Define to 1 if you have the `pututline' function. */ +/* #undef HAVE_PUTUTLINE */ + +/* Define to 1 if you have the `pututxline' function. */ +/* #undef HAVE_PUTUTXLINE */ + +/* Define if your password has a pw_change field */ +/* #undef HAVE_PW_CHANGE_IN_PASSWD */ + +/* Define if your password has a pw_class field */ +/* #undef HAVE_PW_CLASS_IN_PASSWD */ + +/* Define if your password has a pw_expire field */ +/* #undef HAVE_PW_EXPIRE_IN_PASSWD */ + +/* Define to 1 if you have the `readpassphrase' function. */ +/* #undef HAVE_READPASSPHRASE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READPASSPHRASE_H */ + +/* Define to 1 if you have the `realpath' function. */ +/* #define HAVE_REALPATH 1 */ + +/* Define to 1 if you have the `recvmsg' function. */ +/* #undef HAVE_RECVMSG */ + +/* sys/resource.h has RLIMIT_NPROC */ +/* #undef HAVE_RLIMIT_NPROC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_RPC_TYPES_H */ + +/* Define to 1 if you have the `rresvport_af' function. */ +/* #undef HAVE_RRESVPORT_AF */ + +/* Define to 1 if you have the `RSA_generate_key_ex' function. */ +#define HAVE_RSA_GENERATE_KEY_EX 1 + +/* Define to 1 if you have the `RSA_get_default_method' function. */ +#define HAVE_RSA_GET_DEFAULT_METHOD 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SANDBOX_H */ + +/* Define to 1 if you have the `sandbox_init' function. */ +/* #undef HAVE_SANDBOX_INIT */ + +/* define if you have sa_family_t data type */ +/* #undef HAVE_SA_FAMILY_T */ + +/* Define if you have SecureWare-based + protected password database */ +/* #undef HAVE_SECUREWARE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SECURITY_PAM_APPL_H */ + +/* Define to 1 if you have the `sendmsg' function. */ +/* #undef HAVE_SENDMSG */ + +/* Define to 1 if you have the `setauthdb' function. */ +/* #undef HAVE_SETAUTHDB */ + +/* Define to 1 if you have the `setdtablesize' function. */ +/* #undef HAVE_SETDTABLESIZE */ + +/* Define to 1 if you have the `setegid' function. */ +/* #undef HAVE_SETEGID */ + +/* Define to 1 if you have the `setenv' function. */ +/* #undef HAVE_SETENV */ + +/* Define to 1 if you have the `seteuid' function. */ +/* #undef HAVE_SETEUID */ + +/* Define to 1 if you have the `setgroupent' function. */ +/* #undef HAVE_SETGROUPENT */ + +/* Define to 1 if you have the `setgroups' function. */ +/* #undef HAVE_SETGROUPS */ + +/* Define to 1 if you have the `setlogin' function. */ +/* #undef HAVE_SETLOGIN */ + +/* Define to 1 if you have the `setluid' function. */ +/* #undef HAVE_SETLUID */ + +/* Define to 1 if you have the `setpcred' function. */ +/* #undef HAVE_SETPCRED */ + +/* Define to 1 if you have the `setproctitle' function. */ +/* #undef HAVE_SETPROCTITLE */ + +/* Define to 1 if you have the `setregid' function. */ +/* #undef HAVE_SETREGID */ + +/* Define to 1 if you have the `setresgid' function. */ +/* #undef HAVE_SETRESGID */ + +/* Define to 1 if you have the `setresuid' function. */ +/* #undef HAVE_SETRESUID */ + +/* Define to 1 if you have the `setreuid' function. */ +/* #undef HAVE_SETREUID */ + +/* Define to 1 if you have the `setrlimit' function. */ +/* #undef HAVE_SETRLIMIT */ + +/* Define to 1 if you have the `setsid' function. */ +#define HAVE_SETSID 1 + +/* Define to 1 if you have the `setutent' function. */ +/* #undef HAVE_SETUTENT */ + +/* Define to 1 if you have the `setutxdb' function. */ +/* #undef HAVE_SETUTXDB */ + +/* Define to 1 if you have the `setutxent' function. */ +/* #undef HAVE_SETUTXENT */ + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `set_id' function. */ +/* #undef HAVE_SET_ID */ + +/* Define to 1 if you have the `SHA256_Update' function. */ +#define HAVE_SHA256_UPDATE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHA2_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define to 1 if you have the `sigaction' function. */ +/* #undef HAVE_SIGACTION */ + +/* Define to 1 if you have the `sigvec' function. */ +/* #undef HAVE_SIGVEC */ + +/* Define to 1 if the system has the type `sig_atomic_t'. */ +#define HAVE_SIG_ATOMIC_T 1 + +/* define if you have size_t data type */ +#define HAVE_SIZE_T 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `socketpair' function. */ +/* #undef HAVE_SOCKETPAIR */ + +/* Have PEERCRED socket option */ +/* #undef HAVE_SO_PEERCRED */ + +/* define if you have ssize_t data type */ +#define HAVE_SSIZE_T 1 + +/* Fields in struct sockaddr_storage */ +#define HAVE_SS_FAMILY_IN_SS 1 + +/* Define to 1 if you have the `statfs' function. */ +/* #undef HAVE_STATFS */ + +/* Define to 1 if you have the `statvfs' function. */ +#define HAVE_STATVFS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Silly mkstemp() */ +/* #undef HAVE_STRICT_MKSTEMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcat' function. */ +/* #undef HAVE_STRLCAT */ + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ + +/* Define to 1 if you have the `strmode' function. */ +/* #undef HAVE_STRMODE */ + +/* Define to 1 if you have the `strnvis' function. */ +/* #undef HAVE_STRNVIS */ + +/* Define to 1 if you have the `strptime' function. */ +/* #undef HAVE_STRPTIME */ + +/* Define to 1 if you have the `strsep' function. */ +/* #undef HAVE_STRSEP */ + +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if you have the `strtonum' function. */ +/* #undef HAVE_STRTONUM */ + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* define if you have struct addrinfo data type */ +#define HAVE_STRUCT_ADDRINFO 1 + +/* define if you have struct in6_addr data type */ +/* #undef HAVE_STRUCT_IN6_ADDR */ + +/* define if you have struct sockaddr_in6 data type */ +/* #undef HAVE_STRUCT_SOCKADDR_IN6 */ + +/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ +/* #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ + +/* define if you have struct sockaddr_storage data type */ +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ + +/* Define to 1 if the system has the type `struct timespec'. */ +/* #undef HAVE_STRUCT_TIMESPEC */ + +/* define if you have struct timeval */ +#define HAVE_STRUCT_TIMEVAL 1 + +/* Define to 1 if you have the `swap32' function. */ +/* #undef HAVE_SWAP32 */ + +/* Define to 1 if you have the `sysconf' function. */ +/* #undef HAVE_SYSCONF */ + +/* Define if you have syslen in utmpx.h */ +/* #undef HAVE_SYSLEN_IN_UTMPX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_AUDIT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BITYPES_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BSDTTY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_CDEFS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if your system defines sys_errlist[] */ +/* #undef HAVE_SYS_ERRLIST */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MOUNT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if your system defines sys_nerr */ +/* #undef HAVE_SYS_NERR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_POLL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PRCTL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PSTAT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PTMS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STREAM_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STROPTS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_STRTIO_H */ + +/* Force use of sys/syslog.h on Ultrix */ +/* #undef HAVE_SYS_SYSLOG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSMACROS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIMERS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UN_H */ + +/* Define to 1 if you have the `tcgetpgrp' function. */ +/* #undef HAVE_TCGETPGRP */ + +/* Define to 1 if you have the `tcsendbreak' function. */ +/* #undef HAVE_TCSENDBREAK */ + +/* Define to 1 if you have the `time' function. */ +#define HAVE_TIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define if you have ut_time in utmp.h */ +/* #undef HAVE_TIME_IN_UTMP */ + +/* Define if you have ut_time in utmpx.h */ +/* #undef HAVE_TIME_IN_UTMPX */ + +/* Define to 1 if you have the `timingsafe_bcmp' function. */ +/* #undef HAVE_TIMINGSAFE_BCMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TMPDIR_H */ + +/* Define to 1 if you have the `truncate' function. */ +/* #undef HAVE_TRUNCATE */ + +/* Define to 1 if you have tty support */ +/* #undef HAVE_TTY */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_TTYENT_H */ + +/* Define if you have ut_tv in utmp.h */ +/* #undef HAVE_TV_IN_UTMP */ + +/* Define if you have ut_tv in utmpx.h */ +/* #undef HAVE_TV_IN_UTMPX */ + +/* Define if you have ut_type in utmp.h */ +/* #undef HAVE_TYPE_IN_UTMP */ + +/* Define if you have ut_type in utmpx.h */ +/* #undef HAVE_TYPE_IN_UTMPX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UCRED_H */ + +/* define if you have uintxx_t data type */ +#define HAVE_UINTXX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +/* #undef HAVE_UNSETENV */ + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if you have the `updwtmp' function. */ +/* #undef HAVE_UPDWTMP */ + +/* Define to 1 if you have the `updwtmpx' function. */ +/* #undef HAVE_UPDWTMPX */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_USERSEC_H */ + +/* Define to 1 if you have the `user_from_uid' function. */ +#define HAVE_USER_FROM_UID 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTIL_H */ + +/* Define to 1 if you have the `utimes' function. */ +#define HAVE_UTIMES 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTIME_H */ + +/* Define to 1 if you have the `utmpname' function. */ +/* #undef HAVE_UTMPNAME */ + +/* Define to 1 if you have the `utmpxname' function. */ +/* #undef HAVE_UTMPXNAME */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTMPX_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UTMP_H */ + +/* define if you have u_char data type */ +/* #undef HAVE_U_CHAR */ + +/* define if you have u_int data type */ +/* #undef HAVE_U_INT */ + +/* define if you have u_int64_t data type */ +/* #undef HAVE_U_INT64_T */ + +/* define if you have u_intxx_t data type */ +/* #undef HAVE_U_INTXX_T */ + +/* Define to 1 if you have the `vasprintf' function. */ +/* #undef HAVE_VASPRINTF */ + +/* Define if va_copy exists */ +#define HAVE_VA_COPY 1 + +/* Define to 1 if you have the `vhangup' function. */ +/* #undef HAVE_VHANGUP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VIS_H */ + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if you have the `_getlong' function. */ +/* #undef HAVE__GETLONG */ + +/* Define to 1 if you have the `_getpty' function. */ +/* #undef HAVE__GETPTY */ + +/* Define to 1 if you have the `_getshort' function. */ +/* #undef HAVE__GETSHORT */ + +/* Define if you have struct __res_state _res as an extern */ +#define HAVE__RES_EXTERN 1 + +/* Define to 1 if you have the `__b64_ntop' function. */ +/* #undef HAVE___B64_NTOP */ + +/* Define to 1 if you have the `__b64_pton' function. */ +/* #undef HAVE___B64_PTON */ + +/* Define if compiler implements __FUNCTION__ */ +#define HAVE___FUNCTION__ 1 + +/* Define if libc defines __progname */ +/* #undef HAVE___PROGNAME */ + +/* Fields in struct sockaddr_storage */ +/* #undef HAVE___SS_FAMILY_IN_SS */ + +/* Define if __va_copy exists */ +#define HAVE___VA_COPY 1 + +/* Define if compiler implements __func__ */ +#define HAVE___func__ 1 + +/* Define this if you are using the Heimdal + version of Kerberos V5 */ +/* #undef HEIMDAL */ + +/* Define if you need to use IP address + instead of hostname in $DISPLAY */ +/* #undef IPADDR_IN_DISPLAY */ + +/* Detect IPv4 in IPv6 mapped addresses + and treat as IPv4 */ +/* #undef IPV4_IN_IPV6 */ + +/* Define if your system choked on IP TOS setting */ +#define IP_TOS_IS_BROKEN 1 + +/* Define if you want Kerberos 5 support */ +/* #undef KRB5 */ + +/* Define if pututxline updates lastlog too */ +/* #undef LASTLOG_WRITE_PUTUTXLINE */ + +/* Define if you want + TCP Wrappers support */ +/* #undef LIBWRAP */ + +/* Define to whatever link() returns for "not supported" + if it doesn't return + EOPNOTSUPP. */ +/* #undef LINK_OPNOTSUPP_ERRNO */ + +/* Adjust Linux out-of-memory killer */ +/* #undef LINUX_OOM_ADJUST */ + +/* max value of long long calculated by configure */ +/* #undef LLONG_MAX */ + +/* min value of long long calculated by configure */ +/* #undef LLONG_MIN */ + +/* Account locked with pw(1) */ +/* #undef LOCKED_PASSWD_PREFIX */ + +/* String used in /etc/passwd to denote locked account */ +/* #undef LOCKED_PASSWD_STRING */ + +/* String used in /etc/passwd to denote locked account */ +/* #undef LOCKED_PASSWD_SUBSTR */ + +/* Some versions of /bin/login need the TERM supplied + on the commandline */ +/* #undef LOGIN_NEEDS_TERM */ + +/* Some systems need a utmpx entry for /bin/login to work */ +/* #undef LOGIN_NEEDS_UTMPX */ + +/* Define if your login program cannot handle end of options ("--") */ +/* #undef LOGIN_NO_ENDOPT */ + +/* If your header files don't define LOGIN_PROGRAM, + then use this (detected) + from environment and PATH */ +#define LOGIN_PROGRAM_FALLBACK "/usr/bin/login" + +/* Set this to your mail directory if you do not have _PATH_MAILDIR */ +#define MAIL_DIRECTORY "/var/spool/mail" + +/* Define on *nto-qnx systems */ +/* #undef MISSING_FD_MASK */ + +/* Define on *nto-qnx systems */ +/* #undef MISSING_HOWMANY */ + +/* Define on *nto-qnx systems */ +/* #undef MISSING_NFDBITS */ + +/* Need setpgrp to acquire controlling tty */ +/* #undef NEED_SETPGRP */ + +/* Define if the concept of ports only accessible to + superusers isn't known + */ +#define NO_IPPORT_RESERVED_CONCEPT 1 + +/* Define if you don't want to use lastlog in session.c */ +/* #undef NO_SSH_LASTLOG */ + +/* Define if X11 doesn't support AF_UNIX sockets on that system */ +#define NO_X11_UNIX_SOCKETS 1 + +/* Define if EVP_DigestUpdate returns void */ +/* #undef OPENSSL_EVP_DIGESTUPDATE_VOID */ + +/* libcrypto includes complete ECC support */ +#define OPENSSL_HAS_ECC 1 + +/* libcrypto is missing AES 192 and 256 bit functions */ +/* #undef OPENSSL_LOBOTOMISED_AES */ + +/* Define if you want OpenSSL's internally seeded PRNG only */ +#define OPENSSL_PRNG_ONLY 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "openssh-unix-dev@mindrot.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "OpenSSH" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "OpenSSH Portable" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "openssh" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "Portable" + +/* Define if you are using Solaris-derived PAM which + passes pam_messages to + the conversation function + with an extra level of indirection */ +/* #undef PAM_SUN_CODEBASE */ + +/* Work around problematic Linux PAM modules handling of PAM_TTY */ +/* #undef PAM_TTY_KLUDGE */ + +/* must supply username to passwd */ +/* #undef PASSWD_NEEDS_USERNAME */ + +/* Port number of PRNGD/EGD random number socket */ +/* #undef PRNGD_PORT */ + +/* Location of PRNGD/EGD random number socket */ +/* #undef PRNGD_SOCKET */ + +/* read(1) can return 0 for a non-closed fd */ +/* #undef PTY_ZEROREAD */ + +/* Sandbox using Darwin sandbox_init(3) */ +/* #undef SANDBOX_DARWIN */ + +/* no privsep sandboxing */ +#define SANDBOX_NULL 1 + +/* Sandbox using setrlimit(2) */ +/* #undef SANDBOX_RLIMIT */ + +/* Sandbox using systrace(4) */ +/* #undef SANDBOX_SYSTRACE */ + +/* Define if your platform breaks doing a seteuid before a setuid */ +/* #undef SETEUID_BREAKS_SETUID */ + +/* The size of `char', as computed by sizeof. */ +#define SIZEOF_CHAR 1 + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `long int', as computed by sizeof. */ +#define SIZEOF_LONG_INT 4 + +/* The size of `long long int', as computed by sizeof. */ +#define SIZEOF_LONG_LONG_INT 8 + +/* The size of `short int', as computed by sizeof. */ +#define SIZEOF_SHORT_INT 2 + +/* Define if you want S/Key support */ +/* #undef SKEY */ + +/* Define if your skeychallenge() + function takes 4 arguments (NetBSD) */ +/* #undef SKEYCHALLENGE_4ARG */ + +/* Define as const if snprintf() can declare const char *fmt */ +#define SNPRINTF_CONST const + +/* Define to a Set Process Title type if your system is + supported by + bsd-setproctitle.c */ +/* #undef SPT_TYPE */ + +/* Define if sshd somehow reacquires a controlling TTY + after setsid() */ +/* #undef SSHD_ACQUIRES_CTTY */ + +/* Define if pam_chauthtok wants real uid set + to the unpriv'ed user */ +/* #undef SSHPAM_CHAUTHTOK_NEEDS_RUID */ + +/* Use audit debugging module */ +/* #undef SSH_AUDIT_EVENTS */ + +/* Windows is sensitive to read buffer size */ +/* #undef SSH_IOBUFSZ */ + +/* non-privileged user for privilege separation */ +#define SSH_PRIVSEP_USER "sshd" + +/* Use tunnel device compatibility to OpenBSD */ +/* #undef SSH_TUN_COMPAT_AF */ + +/* Open tunnel devices the FreeBSD way */ +/* #undef SSH_TUN_FREEBSD */ + +/* Open tunnel devices the Linux tun/tap way */ +/* #undef SSH_TUN_LINUX */ + +/* No layer 2 tunnel support */ +/* #undef SSH_TUN_NO_L2 */ + +/* Open tunnel devices the OpenBSD way */ +/* #undef SSH_TUN_OPENBSD */ + +/* Prepend the address family to IP tunnel traffic */ +/* #undef SSH_TUN_PREPEND_AF */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you want a different $PATH + for the superuser */ +/* #undef SUPERUSER_PATH */ + +/* syslog_r function is safe to use in in a signal handler */ +/* #undef SYSLOG_R_SAFE_IN_SIGHAND */ + +/* Support passwords > 8 chars */ +/* #undef UNIXWARE_LONG_PASSWORDS */ + +/* Specify default $PATH */ +#define USER_PATH "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin" + +/* Define this if you want to use libkafs' AFS support */ +/* #undef USE_AFS */ + +/* Use BSM audit module */ +/* #undef USE_BSM_AUDIT */ + +/* Use btmp to log bad logins */ +/* #undef USE_BTMP */ + +/* Use libedit for sftp */ +/* #undef USE_LIBEDIT */ + +/* Use Linux audit module */ +/* #undef USE_LINUX_AUDIT */ + +/* Enable OpenSSL engine support */ +/* #undef USE_OPENSSL_ENGINE */ + +/* Define if you want to enable PAM support */ +/* #undef USE_PAM */ + +/* Use PIPES instead of a socketpair() */ +#define USE_PIPES 1 + +/* Define if you want to sanitize fds */ +/* #undef USE_SANITISE_STDFD */ + +/* Define if you have Solaris process contracts */ +/* #undef USE_SOLARIS_PROCESS_CONTRACTS */ + +/* Define if you have Solaris projects */ +/* #undef USE_SOLARIS_PROJECTS */ + +/* Define if you shouldn't strip 'tty' from your + ttyname in [uw]tmp */ +/* #undef WITH_ABBREV_NO_TTY */ + +/* Define if you want to enable AIX4's authenticate function */ +/* #undef WITH_AIXAUTHENTICATE */ + +/* Define if you have/want arrays + (cluster-wide session managment, not C + arrays) */ +/* #undef WITH_IRIX_ARRAY */ + +/* Define if you want IRIX audit trails */ +/* #undef WITH_IRIX_AUDIT */ + +/* Define if you want IRIX kernel jobs */ +/* #undef WITH_IRIX_JOBS */ + +/* Define if you want IRIX project management */ +/* #undef WITH_IRIX_PROJECT */ + +/* Define if you want SELinux support. */ +/* #undef WITH_SELINUX */ + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Define if xauth is found in your path */ +/* #undef XAUTH_PATH */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* log for bad login attempts */ +/* #undef _PATH_BTMP */ + +/* Full path of your "passwd" program */ +#define _PATH_PASSWD_PROG "/usr/bin/passwd" + +/* Specify location of ssh.pid */ +#define _PATH_SSH_PIDDIR "." + +/* Define if we don't have struct __res_state in resolv.h */ +#define __res_state state + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* type to use in place of socklen_t if not defined */ +/* #undef socklen_t */ +#define WIN32_LEAN_AND_MEAN 1 +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#define WIN32_FIXME 1 +#define WINDOWS 1 + +/* Define if you must implement a startup_needs function for your platform */ +#define HAVE_STARTUP_NEEDS 1 + +/* Define if your platform uses Winsock instead of BSD sockets (yeah, there are a lot of platforms like this :) */ +#define HAVE_WINSOCK 1 + +#ifndef WIN32 +#define snprintf _snprintf +#endif + +#define BROKEN_READV_COMPARISON + +/* Override detection of some headers and functions on MinGW */ +#undef BROKEN_SNPRINTF +#define GETPGRP_VOID 1 +#undef HAVE_CRYPT_H +#define HAVE_DAEMON 1 +#undef HAVE_ENDIAN_H +#undef HAVE_FCNTL_H +#define HAVE_FREEADDRINFO 1 +#define HAVE_GAI_STRERROR 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETGROUPLIST 1 +#define HAVE_GETNAMEINFO 1 +#undef HAVE_ID_IN_UTMPX +#define HAVE_INET_ATON 1 +#define HAVE_INET_NTOA 1 +#define HAVE_INNETGR 1 +#undef HAVE_LIBCRYPT +#define HAVE_NANOSLEEP 1 +#undef HAVE_PATHS_H +#undef HAVE_PROC_PID +#undef HAVE_PTY_H +#define HAVE_NANOSLEEP 1 +#define HAVE_READPASSPHRASE 1 +#undef HAVE_SIG_ATOMIC_T +#define HAVE_SIZE_T 1 +#undef HAVE_STRERROR +#define HAVE_STRMODE 1 +#undef __USE_W32_SOCKETS + +#ifdef __MINGW32__ /* FIXME: Use autoconf to set this correctly */ +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 +#endif + +/* Define to 1 if you have the locale.h header. */ +#define HAVE_LOCALE_H 1 + +#define HAVE_STRUCT_IN6_ADDR 1 +#define HAVE_STRUCT_SOCKADDR_IN6 1 +#define HAVE_STRUCT_TIMEVAL 1 +#undef HAVE_SYS_CDEFS_H +#undef HAVE_SYS_SYSMACROS_H +#undef HAVE_SYS_MMAN_H +#undef HAVE_SYS_UN_H +#define _STRUCT_WINSIZE 1 + +#define HAVE_TCGETPGRP 1 + +#undef HAVE_TIME + +#define HAVE_VIS_H 1 + +#define MISSING_FD_MASK 1 +#define MISSING_HOWMANY 1 +#define MISSING_NFDBITS 1 + +#undef SSH_PRIVSEP_USER + +#define HAVE_OPENPTY 1 + +/* Fixes for loginrec.c */ +#undef CONF_UTMP_FILE +#undef CONF_WTMPX_FILE +#undef CONF_WTMP_FILE +#undef CONF_UTMPX_FILE +#undef CONF_LASTLOG_FILE + +#define BROKEN_SYS_TERMIO_H + + +#define WITH_OPENSSL 1 +#define HAVE_DECL_NFDBITS 0 +#define HAVE_DECL_HOWMANY 0 +#define HAVE_STRTOULL 1 +#define HAVE_USLEEP 1 + +#if defined ( WIN32 ) +#define __func__ __FUNCTION__ +#endif + +#define PATH_MAX MAX_PATH + +//#define IN_LOOPBACKNET INADDR_LOOPBACK + +#define S_IFIFO 0x1000 +//#define SHUT_RDWR 2 +//#define SHUT_WR 1 +//#define SHUT_RD 0 + +#define HAVE_EXPLICIT_BZERO + +#define HAVE_MBTOWC 1 + +#include +#include + +#define __attribute__(A) + +// define building with MS Visual Studio Compiler and runtime and not with MingW/gcc compiler +#define WIN32_VS 1 + +/* disable inclusion of compatability defitnitions in CRT headers */ +#define __STDC__ 1 + +#define umac128_new umac_new +#define umac128_update umac_update +#define umac_final umac128_final +#define umac_delete umac128_delete + +#define HAVE_MBLEN 1 + +#define SSHDIR "." +#define _PATH_SFTP_SERVER "sftp-server.exe" +#define _PATH_SSH_PROGRAM "ssh.exe" +#define _PATH_LS "dir" diff --git a/contrib/win32/openssh/config.vcxproj b/contrib/win32/openssh/config.vcxproj new file mode 100644 index 000000000..540bf6567 --- /dev/null +++ b/contrib/win32/openssh/config.vcxproj @@ -0,0 +1,204 @@ + + + + + true + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + Win32Proj + config + 8.1 + config + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Utility + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat\includes;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + + + copy /Y $(SolutionDir)config.h.vs $(OpenSSH-Src-Path)\config.h + + + Setup config.h in openssh source path for visual studio + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat\includes;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + + + copy /Y $(SolutionDir)config.h.vs $(OpenSSH-Src-Path)\config.h + + + Setup config.h in openssh source path for visual studio + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat\includes;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + No + true + true + bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + + + copy /Y $(SolutionDir)config.h.vs $(OpenSSH-Src-Path)\config.h + + + Setup config.h in openssh source path for visual studio + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat\includes;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + No + true + true + bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + + + copy /Y $(SolutionDir)config.h.vs $(OpenSSH-Src-Path)\config.h + + + Setup config.h in openssh source path for visual studio + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/config.vcxproj.filters b/contrib/win32/openssh/config.vcxproj.filters new file mode 100644 index 000000000..34783958e --- /dev/null +++ b/contrib/win32/openssh/config.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {C40EA84D-1664-404D-95C2-79A9E794A94D} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {E2570738-658F-4541-9487-90ECF5F26A93} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {464A0812-84B6-4B3D-B5FD-B3E7F0E0C10E} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 new file mode 100644 index 000000000..d9c08cc9d --- /dev/null +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -0,0 +1,43 @@ +$scriptpath = $MyInvocation.MyCommand.Path +$scriptdir = Split-Path $scriptpath + +$sshdpath = Join-Path $scriptdir "sshd.exe" +$sshagentpath = Join-Path $scriptdir "ssh-agent.exe" +$logsdir = Join-Path $scriptdir "logs" + +$ntrights = "ntrights.exe -u `"NT SERVICE\SSHD`" +r SeAssignPrimaryTokenPrivilege" + +if (-not (Test-Path $sshdpath)) { + throw "sshd.exe is not present in script path" +} + +if (Get-Service sshd -ErrorAction SilentlyContinue) +{ + Stop-Service sshd + sc.exe delete sshd 1> null +} + +if (Get-Service ssh-agent -ErrorAction SilentlyContinue) +{ + Stop-Service ssh-agent + sc.exe delete ssh-agent 1> null +} + +New-Service -Name ssh-agent -BinaryPathName $sshagentpath -Description "SSH Agent" -StartupType Manual | Out-Null +cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)' + +New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Deamon" -StartupType Manual -DependsOn ssh-agent | Out-Null +sc.exe config sshd obj= "NT SERVICE\SSHD" + +Push-Location +cd $scriptdir +cmd.exe /c $ntrights +Pop-Location + +mkdir $logsdir > $null +$sddl = "O:SYG:DUD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x12019f;;;S-1-5-80-3847866527-469524349-687026318-516638107-1125189541)" +$acl = Get-Acl -Path $logsdir +$acl.SetSecurityDescriptorSddlForm($sddl) +Set-Acl -Path $logsdir -AclObject $acl +Write-Host -ForegroundColor Green "sshd and ssh-agent services successfully installed" + diff --git a/contrib/win32/openssh/install-sshlsa.ps1 b/contrib/win32/openssh/install-sshlsa.ps1 new file mode 100644 index 000000000..76a4087a9 --- /dev/null +++ b/contrib/win32/openssh/install-sshlsa.ps1 @@ -0,0 +1,10 @@ +Copy-Item -Path $PSScriptRoot\ssh-lsa.dll -Destination "$env:windir\system32" +$subkey = 'SYSTEM\CurrentControlSet\Control\Lsa' +$value = 'Authentication Packages' +$reg = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 0) +$key = $reg.OpenSubKey($subkey, $true) +$arr = $key.GetValue($value) +if ($arr -notcontains 'ssh-lsa') { + $arr += 'ssh-lsa' + $key.SetValue($value, [string[]]$arr, 'MultiString') +} diff --git a/contrib/win32/openssh/keygen.vcxproj b/contrib/win32/openssh/keygen.vcxproj new file mode 100644 index 000000000..9017c4485 --- /dev/null +++ b/contrib/win32/openssh/keygen.vcxproj @@ -0,0 +1,194 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {47496135-131B-41D6-BF2B-EE7144873DD0} + Win32Proj + keygen + 8.1 + ssh-keygen + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + posix_compat.lib;bcrypt.lib;Netapi32.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + posix_compat.lib;bcrypt.lib;Netapi32.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + posix_compat.lib;bcrypt.lib;Netapi32.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + posix_compat.lib;bcrypt.lib;Netapi32.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/keygen.vcxproj.filters b/contrib/win32/openssh/keygen.vcxproj.filters new file mode 100644 index 000000000..dd9dd237d --- /dev/null +++ b/contrib/win32/openssh/keygen.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/libssh.vcxproj b/contrib/win32/openssh/libssh.vcxproj new file mode 100644 index 000000000..deffb3d68 --- /dev/null +++ b/contrib/win32/openssh/libssh.vcxproj @@ -0,0 +1,296 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {05E1115F-8529-46D0-AAAF-52A404CE79A7} + Win32Proj + libssh + 8.1 + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + false + MultiThreadedDebug + CompileAsC + ProgramDatabase + + + Windows + true + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + false + MultiThreadedDebug + CompileAsC + ProgramDatabase + + + Windows + true + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Windows + true + true + true + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;WIN32;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + + + + + + true + + + + + true + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/libssh.vcxproj.filters b/contrib/win32/openssh/libssh.vcxproj.filters new file mode 100644 index 000000000..2cdb21d1f --- /dev/null +++ b/contrib/win32/openssh/libssh.vcxproj.filters @@ -0,0 +1,300 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/openbsd_compat.vcxproj b/contrib/win32/openssh/openbsd_compat.vcxproj new file mode 100644 index 000000000..198ae3dc5 --- /dev/null +++ b/contrib/win32/openssh/openbsd_compat.vcxproj @@ -0,0 +1,265 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {DD483F7D-C553-4740-BC1A-903805AD0174} + Win32Proj + openbsd_compat + 8.1 + + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + true + v140 + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + StaticLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)openbsd-compat;$(OpenSSH-Src-Path)libkrb;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Windows + true + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)openbsd-compat;$(OpenSSH-Src-Path)libkrb;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Windows + true + + + + + Level1 + NotUsing + MaxSpeed + true + true + _LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=0x600;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)openbsd-compat;$(OpenSSH-Src-Path)libkrb;%(AdditionalIncludeDirectories) + MultiThreaded + + + Windows + true + true + true + + + + + Level1 + NotUsing + MaxSpeed + true + true + _LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_WIN32_WINNT=0x600;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)openbsd-compat;$(OpenSSH-Src-Path)libkrb;%(AdditionalIncludeDirectories) + MultiThreaded + true + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/openbsd_compat.vcxproj.filters b/contrib/win32/openssh/openbsd_compat.vcxproj.filters new file mode 100644 index 000000000..978263787 --- /dev/null +++ b/contrib/win32/openssh/openbsd_compat.vcxproj.filters @@ -0,0 +1,303 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/openssh_build.cmd b/contrib/win32/openssh/openssh_build.cmd new file mode 100644 index 000000000..3ddb6a63e --- /dev/null +++ b/contrib/win32/openssh/openssh_build.cmd @@ -0,0 +1,4 @@ +msbuild /property:Configuration=Release /property:Platform=x64 Win32-OpenSSH.sln +msbuild /property:Configuration=Release /property:Platform=x86 Win32-OpenSSH.sln +msbuild /property:Configuration=Debug /property:Platform=x64 Win32-OpenSSH.sln +msbuild /property:Configuration=Debug /property:Platform=x86 Win32-OpenSSH.sln diff --git a/contrib/win32/openssh/paths.targets b/contrib/win32/openssh/paths.targets new file mode 100644 index 000000000..5aa3d0025 --- /dev/null +++ b/contrib/win32/openssh/paths.targets @@ -0,0 +1,14 @@ + + + + $(SolutionDir)..\..\..\ + $(SolutionDir)..\..\..\bin\ + $(SolutionDir)lib\ + $(SolutionDir)\OpenSSLSDK\1.0.2d + $(SolutionDir)\OpenSSLSDK\1.0.2d\Win32\Release\ + $(SolutionDir)\OpenSSLSDK\1.0.2d\Win32\Debug\ + $(SolutionDir)\OpenSSLSDK\1.0.2d\x64\Release\ + $(SolutionDir)\OpenSSLSDK\1.0.2d\x64\Debug\ + + + \ No newline at end of file diff --git a/contrib/win32/openssh/resource.h b/contrib/win32/openssh/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..3c7d7cdea0fa139e16caad54b7749f021f4807d7 GIT binary patch literal 812 zcmb7?K}*9x5QX1a@INeg6pRJ`KumfFwy89x=qcDXkxFSHX{sXrb@kg_3(-TU4BMTV z&b;^XlCRG|f!>K!6BUXz)Ga4^G8${8g=%fpa4PNS&FD31^{6#f zq;taPNu@TNn*NS^NpD4G!Bk6CQde}=WEUNV94tRQ*Bdi?s+!&kz73N#2nRj(KI8`F zrCyyPi(bLof^HS=owk;4<5;(#7^m)qd#kyg`ES8&)4{XIXYf`|ZN+4WLz(WB<5A*V zOJJRm-QZR1cKybtXJ^W6$n=EWksk0q<9DoUIwNw=>z~0oW}Pa2xC?fMx<^AHi<7aF zlSSkON9nY~z3EDNitU&)cWkfa=kY^~5`A-$g&J R^{4BJ{Z^OmU3;eA^*82mbb0^) literal 0 HcmV?d00001 diff --git a/contrib/win32/openssh/scp.vcxproj b/contrib/win32/openssh/scp.vcxproj new file mode 100644 index 000000000..2d331044b --- /dev/null +++ b/contrib/win32/openssh/scp.vcxproj @@ -0,0 +1,192 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + {29B98ADF-1285-49CE-BF6C-AA92C5D2FB24} + Win32Proj + keygen + 8.1 + scp + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/scp.vcxproj.filters b/contrib/win32/openssh/scp.vcxproj.filters new file mode 100644 index 000000000..fccf50e03 --- /dev/null +++ b/contrib/win32/openssh/scp.vcxproj.filters @@ -0,0 +1,30 @@ + + + + + {C40EA84D-1664-404D-95C2-79A9E794A94D} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {E2570738-658F-4541-9487-90ECF5F26A93} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {464A0812-84B6-4B3D-B5FD-B3E7F0E0C10E} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sftp-server.vcxproj b/contrib/win32/openssh/sftp-server.vcxproj new file mode 100644 index 000000000..29944bb0b --- /dev/null +++ b/contrib/win32/openssh/sftp-server.vcxproj @@ -0,0 +1,196 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + {6657614F-7821-4D55-96EF-7C3C4B551880} + Win32Proj + keygen + 8.1 + sftp-server + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sftp-server.vcxproj.filters b/contrib/win32/openssh/sftp-server.vcxproj.filters new file mode 100644 index 000000000..7e84e8c2d --- /dev/null +++ b/contrib/win32/openssh/sftp-server.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sftp.vcxproj b/contrib/win32/openssh/sftp.vcxproj new file mode 100644 index 000000000..f11a60a58 --- /dev/null +++ b/contrib/win32/openssh/sftp.vcxproj @@ -0,0 +1,198 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + {BBEFF9D7-0BC3-41D1-908B-8052158B5052} + Win32Proj + keygen + 8.1 + sftp + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sftp.vcxproj.filters b/contrib/win32/openssh/sftp.vcxproj.filters new file mode 100644 index 000000000..04bc65203 --- /dev/null +++ b/contrib/win32/openssh/sftp.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-add.vcxproj b/contrib/win32/openssh/ssh-add.vcxproj new file mode 100644 index 000000000..2b95003e9 --- /dev/null +++ b/contrib/win32/openssh/ssh-add.vcxproj @@ -0,0 +1,197 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + {029797FF-C986-43DE-95CD-2E771E86AEBC} + Win32Proj + keygen + 8.1 + ssh-add + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + posix_compat.lib;Netapi32.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x501;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + posix_compat.lib;Netapi32.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + posix_compat.lib;Netapi32.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x501;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + posix_compat.lib;Netapi32.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + wmainCRTStartup + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-add.vcxproj.filters b/contrib/win32/openssh/ssh-add.vcxproj.filters new file mode 100644 index 000000000..12e01f9c0 --- /dev/null +++ b/contrib/win32/openssh/ssh-add.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Header Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-agent.vcxproj b/contrib/win32/openssh/ssh-agent.vcxproj new file mode 100644 index 000000000..376d6e11d --- /dev/null +++ b/contrib/win32/openssh/ssh-agent.vcxproj @@ -0,0 +1,220 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F6644EC5-D6B6-42A1-828C-75E2977470E0} + Win32Proj + Win32OpenSSH + 8.1 + ssh-agent + + + + Application + true + v140 + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + $(Platform)\$(Configuration)\$(TargetName)\ + ssh-agent + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(Platform)\$(Configuration)\$(TargetName)\ + ssh-agent + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + ssh-agent + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + ssh-agent + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories);$(OpenSSH-Src-Path)contrib\win32\ssh-pubkey + CompileAsC + MultiThreadedDebug + Sync + ProgramDatabase + + + Console + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Crypt32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + targetos.manifest + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories);$(OpenSSH-Src-Path)contrib\win32\ssh-pubkey + CompileAsC + MultiThreadedDebug + ProgramDatabase + + + Console + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Crypt32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories);$(OpenSSH-Src-Path)contrib\win32\ssh-pubkey + MultiThreaded + + + Console + true + true + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Crypt32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories);$(OpenSSH-Src-Path)contrib\win32\ssh-pubkey + MultiThreaded + true + + + Console + true + true + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;Crypt32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + targetos.manifest + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-lsa.def b/contrib/win32/openssh/ssh-lsa.def new file mode 100644 index 000000000..b77cde063 --- /dev/null +++ b/contrib/win32/openssh/ssh-lsa.def @@ -0,0 +1,11 @@ +; ssh-lsa.def : Declares the module parameters. + +LIBRARY "ssh-lsa.DLL" + +EXPORTS + LsaApInitializePackage @1 + LsaApLogonUser @2 + LsaApLogonTerminated @3 + LsaApCallPackagePassthrough @4 + LsaApCallPackageUntrusted @5 + LsaApCallPackage @6 \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-lsa.vcxproj b/contrib/win32/openssh/ssh-lsa.vcxproj new file mode 100644 index 000000000..183ee8a4a --- /dev/null +++ b/contrib/win32/openssh/ssh-lsa.vcxproj @@ -0,0 +1,189 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + {02FB3D98-6516-42C6-9762-98811A99960F} + Win32Proj + ssh-lsa + 8.1 + ssh-lsa + + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + + + + Level3 + Disabled + _WIN32_WINNT=0x600;__VS_BUILD__=1;__VS_BUILD__WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + $(OpenSSL-Win32-Debug-Path)include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + advapi32.lib + $(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + ssh-lsa.def + + + + + + + Level3 + Disabled + _WIN32_WINNT=0x600;__VS_BUILD__=1;__VS_BUILD__WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + $(OpenSSL-x64-Debug-Path)include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + advapi32.lib + $(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + ssh-lsa.def + + + + + Level3 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;__VS_BUILD__=1;__VS_BUILD___LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(OpenSSL-Win32-Release-Path)include;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + advapi32.lib + $(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + ssh-lsa.def + + + + + Level3 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;__VS_BUILD__=1;__VS_BUILD___LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(OpenSSL-x64-Release-Path)include;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + advapi32.lib + $(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + ssh-lsa.def + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-lsa.vcxproj.filters b/contrib/win32/openssh/ssh-lsa.vcxproj.filters new file mode 100644 index 000000000..44c766469 --- /dev/null +++ b/contrib/win32/openssh/ssh-lsa.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {6CB7C14F-01AD-4B45-B64B-7CA809717A41} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {E208189E-89FC-415D-B803-9FE16836833A} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {A4657585-A2AC-4675-8657-EE71F3E97A4D} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh-shellhost.vcxproj b/contrib/win32/openssh/ssh-shellhost.vcxproj new file mode 100644 index 000000000..d2cd41580 --- /dev/null +++ b/contrib/win32/openssh/ssh-shellhost.vcxproj @@ -0,0 +1,188 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + {C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64} + Win32Proj + shellhost + 8.1 + ssh-shellhost + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + + + MultiThreadedDebug + ProgramDatabase + + + Console + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + + + MultiThreadedDebug + ProgramDatabase + + + Console + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + + + MultiThreaded + + + Console + true + true + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + + + MultiThreaded + + + Console + true + true + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh.vcxproj b/contrib/win32/openssh/ssh.vcxproj new file mode 100644 index 000000000..571b3519a --- /dev/null +++ b/contrib/win32/openssh/ssh.vcxproj @@ -0,0 +1,308 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {74E69D5E-A1EF-46EA-9173-19A412774104} + Win32Proj + Win32OpenSSH + 8.1 + ssh + + + + Application + true + v140 + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + $(Platform)\$(Configuration)\$(TargetName)\ + ssh + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(Platform)\$(Configuration)\$(TargetName)\ + ssh + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + ssh + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + ssh + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + CompileAsC + MultiThreadedDebug + Sync + ProgramDatabase + + + Console + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + wmainCRTStartup + + + targetos.manifest + + + + + NotUsing + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + CompileAsC + MultiThreadedDebug + ProgramDatabase + + + Console + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + wmainCRTStartup + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + wmainCRTStartup + + + targetos.manifest + + + + + Level1 + NotUsing + MaxSpeed + true + true + _WIN32_WINNT=0x600;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + true + + + Console + true + true + true + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + wmainCRTStartup + + + targetos.manifest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/ssh.vcxproj.filters b/contrib/win32/openssh/ssh.vcxproj.filters new file mode 100644 index 000000000..56187a3e8 --- /dev/null +++ b/contrib/win32/openssh/ssh.vcxproj.filters @@ -0,0 +1,320 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sshd.vcxproj b/contrib/win32/openssh/sshd.vcxproj new file mode 100644 index 000000000..e2da8f938 --- /dev/null +++ b/contrib/win32/openssh/sshd.vcxproj @@ -0,0 +1,254 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {F58FF6BA-098B-4DB9-9609-A030DFB4D03F} + Win32Proj + keygen + 8.1 + sshd + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + true + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + false + $(OpenSSH-Bin-Path)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(TargetName)\ + $(OpenSSH-Src-Path)contrib\win32\win32compat\inc;$(VC_IncludePath);$(WindowsSDK_IncludePath); + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32_ZLIB_NO;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;Netapi32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) + MultiplyDefinedSymbolOnly + wmainCRTStartup + + + targetos.manifest + + + + + + + Level1 + Disabled + _WIN32_WINNT=0x600;WIN32_ZLIB_NO;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Debug-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreadedDebug + ProgramDatabase + + + Console + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;Netapi32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) + MultiplyDefinedSymbolOnly + wmainCRTStartup + + + targetos.manifest + + + + + Level1 + + + MaxSpeed + true + true + _WIN32_WINNT=0x600;WIN32_ZLIB_NO;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-Win32-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;Netapi32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) + MultiplyDefinedSymbolOnly + wmainCRTStartup + + + targetos.manifest + + + + + Level1 + + + Disabled + true + true + _WIN32_WINNT=0x600;WIN32_ZLIB_NO;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(SolutionDir);$(OpenSSL-x64-Release-Path)include;$(OpenSSH-Src-Path)includes;$(OpenSSH-Src-Path);$(OpenSSH-Src-Path)contrib\win32\win32compat;$(OpenSSH-Src-Path)libkrb;$(OpenSSH-Src-Path)libkrb\libKrb5;%(AdditionalIncludeDirectories) + MultiThreaded + false + + + Console + true + true + true + Netapi32.lib;posix_compat.lib;bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;libeay32.lib;Netapi32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) + MultiplyDefinedSymbolOnly + wmainCRTStartup + + + targetos.manifest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sshd.vcxproj.filters b/contrib/win32/openssh/sshd.vcxproj.filters new file mode 100644 index 000000000..cd2c9120e --- /dev/null +++ b/contrib/win32/openssh/sshd.vcxproj.filters @@ -0,0 +1,159 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/contrib/win32/openssh/sshd_config b/contrib/win32/openssh/sshd_config new file mode 100644 index 000000000..78ce20a7f --- /dev/null +++ b/contrib/win32/openssh/sshd_config @@ -0,0 +1,122 @@ +# $OpenBSD: sshd_config,v 1.84 2011/05/23 03:30:07 djm Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +# The default requires explicit activation of protocol 1 +#Protocol 2 + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 1024 + +# Logging +# obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +#PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#RSAAuthentication yes +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +#UsePAM no + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 +#PermitTunnel no +#ChrootDirectory none + +# no default banner path +#Banner none + +# override default of no subsystems +Subsystem sftp C:/Program Files/OpenSSH/sftp-server.exe + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# ForceCommand cvs server +PubkeyAcceptedKeyTypes ssh-ed25519* \ No newline at end of file diff --git a/contrib/win32/openssh/targetos.manifest b/contrib/win32/openssh/targetos.manifest new file mode 100644 index 000000000..44b37135f --- /dev/null +++ b/contrib/win32/openssh/targetos.manifest @@ -0,0 +1,17 @@ + + + + + + + * + * + + + + + + + + + \ No newline at end of file diff --git a/contrib/win32/openssh/uninstall-sshd.ps1 b/contrib/win32/openssh/uninstall-sshd.ps1 new file mode 100644 index 000000000..8f0cd90f4 --- /dev/null +++ b/contrib/win32/openssh/uninstall-sshd.ps1 @@ -0,0 +1,22 @@ +if (Get-Service sshd -ErrorAction SilentlyContinue) +{ + Stop-Service sshd + sc.exe delete sshd 1> null + Write-Host -ForegroundColor Green "sshd successfully uninstalled" +} +else { + Write-Host -ForegroundColor Yellow "sshd service is not installed" +} + +if (Get-Service ssh-agent -ErrorAction SilentlyContinue) +{ + Stop-Service ssh-agent + sc.exe delete ssh-agent 1>null + Write-Host -ForegroundColor Green "ssh-agent successfully uninstalled" +} +else { + Write-Host -ForegroundColor Yellow "ssh-agent service is not installed" +} + + + diff --git a/contrib/win32/openssh/uninstall-sshlsa.ps1 b/contrib/win32/openssh/uninstall-sshlsa.ps1 new file mode 100644 index 000000000..c99390ca8 --- /dev/null +++ b/contrib/win32/openssh/uninstall-sshlsa.ps1 @@ -0,0 +1,10 @@ +$subkey = 'SYSTEM\CurrentControlSet\Control\Lsa' +$value = 'Authentication Packages' +$reg = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine', 0) +$key = $reg.OpenSubKey($subkey, $true) +$arr = $key.GetValue($value) +if ($arr -contains 'ssh-lsa') { + $tempArryList = New-Object System.Collections.Arraylist(,$arr) + $tempArryList.Remove('ssh-lsa') + $key.SetValue($value, [string[]]$tempArryList, 'MultiString') +} diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc new file mode 100644 index 0000000000000000000000000000000000000000..6242ddcbf8c816c083478cc6f6b1485c2dfabfe2 GIT binary patch literal 4046 zcmdUy-)|B@5Xa})#Q)*EzS!7MkoLjHwoppsS9*Y&G$B}^k{}okq7VM<>SuP@-W_*f zMIX*=j@_G^nVp~CU4H&Jl~eJgDO0(Zr7R@mnaB!SA6h7D8On^eD|yB6Yla7n`)cN7kCQtT%NJZshN+U&iOindt`Y1lzc%xiEp@7^2qQ_jGXGe zkd6e>m7Y|jE^QgetyG~_Shu7hAD{&MHsumZgSFdVZOGqn*16e}8gbc<@q{QXpggi`Vb@t>g6-eri0b&|mXxXXN)e_-f*7<&yEwU&Ne6wmR0tN-JrC--p$Pi@ejD zui07Wk=;4{HzQLaHQ>ohaz5wH^OMI^xq)={eGqREQ zPKq1!)%@9rsg&Z%A$w#YzAtIK@#PNOx}%~k_D5FkvZ#EZMSr@_k-_5;ou(LLhhjt) z-lVI|&jh{p@^;ponjKHWEfr%Im(<_vD}uAX1hXDS{4;^->v z!BMBLt6MxCHFsj3b2D4s4*J_vU=IZ9K1sr9zc$!W!@4FI643j)!#63D!G`fit1?0j zMYk%5)1yn0c1D`4hSH<_7$gpf(|-P9j9$TvZDgWob-B-Uu+Z{3 zozZuTm)Ts|y|3unCaxM89}8CGTW@9$WN3h|t;Xlcpr|(Z`?VW9$yeZ!!yAv<-A(Mfj*Dg7ihQlr!rk>g2aEKdc=}&WI`69K7b2 + * + * Copyright (c) 2009, 2011 NoMachine + * All rights reserved + * + * Support functions and system calls' replacements needed to let the + * software run on Win32 based operating systems. + * + * 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. + */ + +#ifndef Debug_H +#define Debug_H + +#define FAIL(CONDITION) if (CONDITION) goto fail + +#define NTFAIL(NTFUNC) if((ntStat = (NTFUNC))) goto fail + +#endif diff --git a/contrib/win32/win32compat/ansiprsr.c b/contrib/win32/win32compat/ansiprsr.c new file mode 100644 index 000000000..9ebd12d01 --- /dev/null +++ b/contrib/win32/win32compat/ansiprsr.c @@ -0,0 +1,1000 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* ansiprsr.c + * + * ANSI Parser to run on Win32 based operating systems. + * + */ + +#include +#include +#include +#include + + +#include + +#include "ansiprsr.h" +#include "tncon.h" +#include "tnnet.h" + +#define TS_IS 0 +#define TS_SEND 1 + +// items used from other modules +TelParams Parameters; + +extern int ScreenX; +extern int ScreenY; +extern int ScrollTop; +extern int ScrollBottom; + +// end of imports from outside module + +bool gbVTAppMode = false; + +// private message for port printing to +unsigned char VT_ST[] = { 0x1b, '/', '\0' }; + +static int AutoWrap = 1; + +BOOL bAtEOLN = FALSE; + +static int term_mode; + +// ParseANSI globals - these need to be here, because sometimes blocks are sent +// in mid ANSI sequence +int iParam[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +int iCurrentParam = 0; +int bDelimiter = 0; +int bMode = 0; +int fcompletion = 1; +int bExtMode = 0; +int bCS0 = 0; +int bCS1 = 0; +int bBkMode = 0; +int bCharMode = 0; +int ReportedX = 0; +int ReportedY = 0; + +BOOL fShiftOut = FALSE; +BOOL InPrintMode = FALSE; +BOOL fPcMode = FALSE; + +char printErr[] = "Unable to Print: Printer not assigned. Press any key to continue..."; +char cursor_report[255]; + +#define MODE_CURSORAPP 0x0001 +#define MODE_ANSIVT52 0x0002 +#define MODE_COL132 0x0004 +#define MODE_SMOOTHSCROLL 0x0008 +#define MODE_REVERSESCREEN 0x0010 +#define MODE_ORIGINREL 0x0020 +#define MODE_WRAPAROUND 0x0040 +#define MODE_AUTOREPEAT 0x0080 +#define MODE_APPMODE 0x0100 +#define MODE_LNM 0x0200 +#define MODE_IRM_INSERT 0x0400 + +int VTMode = 0; + +#define MODE_CURSORAPP 0x0001 +#define MODE_ANSIVT52 0x0002 +#define MODE_COL132 0x0004 +#define MODE_SMOOTHSCROLL 0x0008 +#define MODE_REVERSESCREEN 0x0010 +#define MODE_ORIGINREL 0x0020 +#define MODE_WRAPAROUND 0x0040 +#define MODE_AUTOREPEAT 0x0080 +#define MODE_APPMODE 0x0100 +#define MODE_LNM 0x0200 + +char *GetTerminalId() +{ + return TERMINAL_ID; +} + +char * GetStatusReport() +{ + return STATUS_REPORT; +} + +char * GetCursorPositionReport() +{ + DWORD wr = 0; + DWORD out = 0; + + out = _snprintf_s(cursor_report, sizeof(cursor_report), _TRUNCATE, + CURSOR_REPORT_FORMAT_STRING, ConGetCursorY() + 1, ConGetCursorX() + 1); + + if (out > 0) { + return cursor_report; + } + + return NULL; +} + +void BufConvertToG2(char * pszBuffer, int length) +{ + int i; + + for (i=0;i= (ConWindowSizeY()-1)) + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + ConMoveCursorPosition(-ConGetCursorX(),1); + bAtEOLN = FALSE; +} + +unsigned char* ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char **respbuf, size_t *resplen) +{ + int CurrentX; + int CurrentY; + int bufLen, cmpLen, i; + + if (!fcompletion) + { + if (pszBuffer < pszBufferEnd - 1) + { + unsigned char * pszCurrent = pszBuffer+1; + unsigned char * pszNewCurrent = pszCurrent; + + if (term_mode == TERM_ANSI) + { + pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen); + } + else if (term_mode == TERM_VT52) + { + pszNewCurrent = ParseVT52(pszCurrent, pszBufferEnd, respbuf, resplen); + } + + if (pszCurrent == pszNewCurrent) // Pointer didn't move inside Parse function + { + pszNewCurrent += ConWriteString( (char *)pszCurrent, 1); + return pszNewCurrent; + } + if (pszNewCurrent > pszCurrent) + pszBuffer = pszNewCurrent; + } + } + + // This is handling special characters including locating the ESC which starts a + // terminal control sequence. + switch ((unsigned char) (*pszBuffer)) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 11: + pszBuffer++; + break; + + case 7: + Beep(1000, 400); + pszBuffer++; + break; + + case 8: + pszBuffer++; + if (!bAtEOLN) + { + CurrentX = ConGetCursorX(); + if (CurrentX == 0) + { + ConMoveCursorPosition(ScreenX-1,-1); + ConWriteString(" ",1); + } + else + { + ConClearNFromCursorLeft(1); + ConMoveCursorPosition(-1, 0); + } + } + bAtEOLN = FALSE; + break; + + case 9: + { + if (bAtEOLN) GoToNextLine(); + int i, MoveRight = 8 - (ConGetCursorX() % 8); + + for ( i = 0; i < MoveRight; i++ ) + ConWriteString( " ", 1 ); + pszBuffer++; + AutoWrap = 1; + bAtEOLN = FALSE; + } + break; + + case 10: + pszBuffer++; + AutoWrap = 1; + bAtEOLN = FALSE; + break; + + case 12: + pszBuffer++; + ConSetCursorPosition(0, 0); + ConClearScreen(); + AutoWrap = 1; + bAtEOLN = FALSE; + break; + + case 13: + pszBuffer++; + AutoWrap = 1; + GoToNextLine(); + break; + + case 14: + pszBuffer++; + fShiftOut = TRUE; + break; + + case 15: + fShiftOut = FALSE; + pszBuffer++; + break; + + case 27: + if (pszBuffer < pszBufferEnd -1) + { + unsigned char * pszCurrent = pszBuffer + 1; + unsigned char * pszNewCurrent = pszCurrent; + + if (*pszCurrent == 27) + { + pszNewCurrent += ConWriteString( (char *)pszCurrent, 1); + return pszBuffer + 1; + } + else + { + if (term_mode == TERM_ANSI) + { + pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen); + } + else if (term_mode == TERM_VT52) + { + pszNewCurrent = ParseVT52(pszCurrent, pszBufferEnd, respbuf, resplen); + } + } + if (pszNewCurrent > pszCurrent) + pszBuffer = pszNewCurrent; + } + break; + + default: + { + if (bAtEOLN) GoToNextLine(); + + unsigned char* pszCurrent = pszBuffer; + CurrentX = ConGetCursorX(); + int nCharCount = 0; + + while ((pszCurrent < pszBufferEnd) && (*pszCurrent != (unsigned char)27) + && (*pszCurrent > (unsigned char)15) && (*pszCurrent != (unsigned char)255) + && (CurrentX++ < ScreenX)) { + if (*pszCurrent > 127) { + unsigned char nLead = *pszCurrent; + nCharCount++; + if ((nLead & 128) == 128) { + pszCurrent++; + } + if ((nLead & 192) == 192) { + pszCurrent++; + } + if ((nLead & 224) == 224) { + pszCurrent++; + } + if ((nLead & 240) == 240) { + pszCurrent++; + } + } + else + pszCurrent++; + } + + if (fShiftOut) + memset(pszBuffer, '|', pszCurrent - pszBuffer); + + pszBuffer += ConWriteString((char *)pszBuffer, (int)(pszCurrent - pszBuffer)); + + if ((CurrentX >= ScreenX) && AutoWrap && !(VTMode & MODE_CURSORAPP)) + { + bAtEOLN = TRUE; + } + } + break; + } + + return pszBuffer; +} + + +unsigned char * GetNextChar(unsigned char *pszBuffer, unsigned char *pszBufferEnd) +{ + if (++pszBuffer > pszBufferEnd) + return NULL; + else + return pszBuffer; +} + +void ConSetExtendedMode(int iFunction, BOOL bEnable) +{ + switch(iFunction) + { + case 1: + if (bEnable){ + VTMode |= MODE_CURSORAPP; + gbVTAppMode = true; + }else{ + VTMode &= ~MODE_CURSORAPP; + gbVTAppMode = false; + } + break; + case 2: + if (!bEnable) + VTMode |= MODE_ANSIVT52; + break; + case 3: + if (bEnable) + VTMode |= MODE_COL132; + else + VTMode &= ~MODE_COL132; + break; + case 4: + if (bEnable) + VTMode |= MODE_SMOOTHSCROLL; + else + VTMode &= ~MODE_SMOOTHSCROLL; + break; + case 5: + if (bEnable) + VTMode |= MODE_REVERSESCREEN; + else + VTMode &= ~MODE_REVERSESCREEN; + break; + case 6: + if (bEnable) + VTMode |= MODE_ORIGINREL; + else + VTMode &= ~MODE_ORIGINREL; + break; + case 7: + if (bEnable) + VTMode |= MODE_WRAPAROUND; + else + VTMode &= ~MODE_WRAPAROUND; + break; + case 8: + if (bEnable) + VTMode |= MODE_AUTOREPEAT; + else + VTMode &= ~MODE_AUTOREPEAT; + break; + case 20: // LNM Mode CSI 20h + if (bEnable){ + VTMode |= MODE_LNM; + Parameters.nReceiveCRLF = ENUM_CRLF; + }else{ + VTMode &= ~MODE_LNM; + Parameters.nReceiveCRLF = ENUM_LF; + } + break; + case 25: + ConDisplayCursor(bEnable); + break; + + } + + if ((iFunction == 2) && (bEnable)) + { + term_mode = TERM_VT52; + } +} + +#define MODE_EXT 0x00000001 +#define MODE_CS0 0x00000002 +#define MODE_CS1 0x00000004 +#define MODE_CS2 0x00000008 +#define MODE_CS3 0x00000010 +#define MODE_BRK 0x00000020 +#define MODE_CHAR 0x00000040 +#define MODE_K 0x00000080 + +#define DIGI_MASK (MODE_CS0 | MODE_CS1 | MODE_CS2 | MODE_CS3 | MODE_CHAR) + +unsigned char * ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char **respbuf, size_t *resplen) +{ + const int nParam = 10; // Maximum number of parameters + + static int SavedX = 0; + static int SavedY = 0; + + unsigned char * pszCurrent = pszBuffer; + + if (pszCurrent == NULL || pszBufferEnd == NULL) + return NULL; + + fcompletion = 0; + do + { + switch ((unsigned char) *pszCurrent) + { +// Delimiter + case ';': + bDelimiter = TRUE; + break; +// Modifiers + case '?': // Extended Mode + bMode |= MODE_EXT; + break; + case '(': + bMode |= MODE_CS0; + break; + case ')': + bMode |= MODE_CS1; + break; + case '*': + bMode |= MODE_CS2; + break; + case '+': + bMode |= MODE_CS3; + break; + case '[': + bMode |= MODE_BRK; + break; + case '#': + bMode |= MODE_CHAR; + break; + +// Termination Options + case 0: + fcompletion = 1; + break; + + case '}': + fcompletion = 1; + break; + + case '<': // Character set + fcompletion = 1; + break; + + case '\\': + fcompletion = 1; + break; + + case '~': + fcompletion = 1; + break; + + case '^': // Private message + while (pszCurrent && pszCurrent < pszBufferEnd && + _strnicmp((const char *)pszCurrent, (const char *)VT_ST, strlen((const char *)VT_ST) ) ) // while not stop + { + if (pszCurrent && pszCurrent < pszBufferEnd && + _strnicmp((const char *)pszCurrent, (const char *)VT_ST, strlen((const char *)VT_ST) ) ) + pszCurrent++; + } + pszCurrent += strlen((const char *)VT_ST) - 1; + fcompletion = 1; + break; + + case 'A': // Character Set change or Cursor Up + if (bMode & MODE_CHAR) + { + } + else if (bMode & MODE_BRK) + { + // Cursor UP + if (iParam[0] == 0) + iParam[0] = 1; + ConMoveCursorPosition(0, -iParam[0]); + } + fcompletion = 1; + break; + + case 'B': // Character set change or Cursor down + if (bMode & MODE_CHAR) + { + // Character Set + } + else if (bMode & MODE_BRK) + { + // Cursor DOWN + if (iParam[0] == 0) + iParam[0] = 1; + ConMoveCursorPosition(0, iParam[0]); + } + fcompletion = 1; + break; + + case 'C': // Character Set change or Cursor right + if (bMode & MODE_CHAR) + { + // Character Set + } + else if (bMode & MODE_BRK) + { + // Cursor right + if (iParam[0] == 0) + iParam[0] = 1; + ConMoveCursorPosition(iParam[0], 0); + + } + fcompletion = 1; + break; + + case 'D': // Cursor left + if (bMode & MODE_BRK) + { + // Cursor left + if (iParam[0] == 0) + iParam[0] = 1; + ConMoveCursorPosition(-iParam[0], 0); + } + else if (bMode == 0) + { + // Index + ConScrollDown(ScrollTop,ScrollBottom); + } + fcompletion = 1; + bAtEOLN = FALSE; + break; + + case '=': // Application mode + VTMode |= MODE_APPMODE; + fcompletion = 1; + break; + + case '>': // Numeric mode + VTMode &= ~MODE_APPMODE; + fcompletion = 1; + break; + + case '%': // Character set definitions + fcompletion = 1; + break; + + case 'h': + if (bMode & MODE_EXT) + { + if (iParam[0] == 4 && iParam[1] == 7) { + ConSaveScreen(); + } + } + case 'l': // ^[?25h + if (bMode & MODE_EXT) + { + if (iParam[0] == 4 && iParam[1] == 7) { + ConRestoreScreen(); + } + else + { + if (iParam[0] == 4) { + VTMode |= MODE_IRM_INSERT; + } + int i; + for (i = 0; i < iCurrentParam; i++) + ConSetExtendedMode(iParam[i], *pszCurrent == 'h' ? 1 : 0); + } + } + else if (bMode & MODE_BRK) + { + // Possible set Line feed (option 20) + if (iParam[0] == 20) + ConSetExtendedMode(iParam[0], *pszCurrent=='h' ? 1 : 0); + if (iParam[0] == 4){ + VTMode &= ~MODE_IRM_INSERT; + } + } + fcompletion = 1; + break; + + case 'L': + if (iParam[0]) + { + int i; + for (i=0; i 0) ? iParam[1] - 1 : 0, (iParam[0] > 0) ? iParam[0] - 1 : 0); + } + else if (bMode == 0) + { + //Set tab + } + fcompletion = 1; + bAtEOLN = FALSE; + break; + + case 'M': + if (iParam[0]) + { + int i ; + for (i=0; i': // Exit Alt Keypad mode + case '1': // Graphics processor on + case '2': // Graphics processor off + pszCurrent++; + break; + + case '<': // Enter ANSI mode + term_mode = TERM_ANSI; + pszCurrent++; + break; + + default: + pszCurrent++; + break; + } + + return pszCurrent; + +} diff --git a/contrib/win32/win32compat/ansiprsr.h b/contrib/win32/win32compat/ansiprsr.h new file mode 100644 index 000000000..c1cbfc45c --- /dev/null +++ b/contrib/win32/win32compat/ansiprsr.h @@ -0,0 +1,81 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* ansiprsr.h + * + * ANSI Parser header file to run on Win32 based operating systems. + * + */ + +#ifndef __ANSIPRSR_H +#define __ANSIPRSR_H + +#define TERM_ANSI 0 +#define TERM_VT52 1 + +unsigned char * ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char **respbuf, size_t *resplen); +unsigned char * GetNextChar(unsigned char * pszBuffer, unsigned char *pszBufferEnd); +unsigned char * ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char **respbuf, size_t *resplen); +unsigned char * ParseVT52(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char **respbuf, size_t *resplen); + +#define true TRUE +#define false FALSE +#define bool BOOL + +#define ENUM_CRLF 0 +#define ENUM_LF 1 +#define ENUM_CR 2 + +typedef struct _TelParams +{ + int fLogging; + FILE *fplogfile; + + char *pInputFile; + + char *szDebugInputFile; + BOOL fDebugWait; + + int timeOut; + int fLocalEcho; + int fTreatLFasCRLF; + int fSendCROnly; + int nReceiveCRLF; + + char sleepChar; + char menuChar; + + SOCKET Socket; + BOOL bVT100Mode; + + char *pAltKey; + +} TelParams; + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/conio.c b/contrib/win32/win32compat/conio.c new file mode 100644 index 000000000..4e406fa5a --- /dev/null +++ b/contrib/win32/win32compat/conio.c @@ -0,0 +1,183 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* conio.c + * + * Inserts data into Windows Console Input. Needed WriteToConsole() API implemented. + * + */ + +#include +#include +#include + +#include + +#include "console.h" +#include + +COORD lastCursorLoc = { 0, 0 }; +BYTE KeyboardState[256]; +INPUT_RECORD srec; +DWORD dwGlobalConsoleMode ; + +int WriteToConsole(HANDLE fd, unsigned char *buf, size_t len, size_t *dwWritten, void *flag) +{ + static KEY_EVENT_RECORD *pkey; + static KEY_EVENT_RECORD *pkey2; + static INPUT_RECORD irec[2]; + static BOOL bInitKeyboard = TRUE; + size_t ctr; + int rc; + DWORD dwRecords; + DWORD vkey; + BOOL bNeedToWait = TRUE; + CONSOLE_SCREEN_BUFFER_INFO csbi; + + int scr_width = 80; /* screen horizontal width, e.g. 80 */ + int scr_height = 25; /* screen vertical length, e.g. 25 */ + char tmpbuf[2]; + int local_echo = 0; + + /* + * Need to set pkey and pkey2 which we use below. Initialize the keyboard state table. + */ + if (bInitKeyboard) + { + GetKeyboardState(KeyboardState); + bInitKeyboard = FALSE; + srec.EventType = KEY_EVENT; + srec.Event.KeyEvent.bKeyDown = TRUE; + srec.Event.KeyEvent.wRepeatCount = 1; + srec.Event.KeyEvent.wVirtualKeyCode = 0x10; + srec.Event.KeyEvent.wVirtualScanCode = 0x2a; + srec.Event.KeyEvent.uChar.AsciiChar = 0; + srec.Event.KeyEvent.uChar.UnicodeChar = 0; + srec.Event.KeyEvent.dwControlKeyState = 0x10; + + irec[0].EventType = KEY_EVENT; /* init key down message */ + pkey = &(irec[0].Event.KeyEvent); + pkey->wRepeatCount = 1; + pkey->bKeyDown = TRUE; + + irec[1].EventType = KEY_EVENT; /* init key up message */ + pkey2 = &(irec[1].Event.KeyEvent); + pkey2->wRepeatCount = 1; + pkey2->bKeyDown = FALSE; + } + + // Stream mode processing + if (local_echo) + { + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + } + + GetConsoleMode(fd, &dwGlobalConsoleMode); + + ctr = 0; + while (ctr < len) + { + if (local_echo) + { + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + lastCursorLoc.Y = csbi.dwCursorPosition.Y; + lastCursorLoc.X = csbi.dwCursorPosition.X; + } + { + pkey->dwControlKeyState = 0x00000000; + pkey->uChar.AsciiChar = buf[ctr]; /* next char in ascii */ + + mbtowc(&(pkey->uChar.UnicodeChar), (const char *)&(buf[ctr]), 1); + vkey = VkKeyScan(pkey->uChar.AsciiChar); + + if ((BYTE)(vkey >> 8) != 0xFF) // high order word + { + if (vkey & 0x0100 || (KeyboardState[VK_LSHIFT] & 0x80)) /* high word gives shift, ctrl, alt status */ + pkey->dwControlKeyState |= SHIFT_PRESSED; /* shift key presssed*/ + if (vkey & 0x0200 || (KeyboardState[VK_LCONTROL] & 0x80)) + pkey->dwControlKeyState |= LEFT_CTRL_PRESSED; /* any ctrl really*/ + if ((vkey & 0x0400) || (KeyboardState[VK_LMENU] & 0x80)) + pkey->dwControlKeyState |= LEFT_ALT_PRESSED; /* any ALT really*/ + } + if ((BYTE)vkey != 0xFF) // low order word + { + pkey->wVirtualKeyCode = (BYTE)vkey; + pkey->wVirtualScanCode = MapVirtualKey(pkey->wVirtualKeyCode, 0); + if (pkey->uChar.UnicodeChar == 0x1b) // stream mode fix for Admark ESC sequences + pkey->wVirtualKeyCode = 0x00db; + + + } + + /* we need to mimic key up and key down */ + if (pkey->dwControlKeyState & 0x0100) + { + srec.Event.KeyEvent.bKeyDown = TRUE; + srec.Event.KeyEvent.dwControlKeyState = 0x10; + WriteConsoleInput(fd, &srec, 1, &dwRecords); /* write shift down */ + tmpbuf[0] = irec[0].Event.KeyEvent.uChar.AsciiChar; + tmpbuf[1] = '\0'; + } + + pkey->bKeyDown = TRUE; /*since pkey is mucked by others we do it again*/ + + /* dup these into key up message structure from key down message */ + pkey2->wVirtualKeyCode = pkey->wVirtualKeyCode; + pkey2->wVirtualScanCode = pkey->wVirtualScanCode; + pkey2->uChar.AsciiChar = pkey->uChar.AsciiChar; + pkey2->uChar.UnicodeChar = pkey->uChar.UnicodeChar; + pkey2->dwControlKeyState = pkey->dwControlKeyState; + + WriteConsoleInput(fd, irec, 2, &dwRecords); /* key down,up msgs */ + tmpbuf[0] = irec[0].Event.KeyEvent.uChar.AsciiChar; + tmpbuf[1] = '\0'; + if (pkey->dwControlKeyState & 0x0100) + { + srec.Event.KeyEvent.bKeyDown = FALSE; + srec.Event.KeyEvent.dwControlKeyState = 0x0; + WriteConsoleInput(fd, &srec, 1, &dwRecords); /* write shift up */ + + } + //if ((local_echo)) + //{ + // bNeedToWait = EchoInputCharacter(buf[ctr], &csbi.dwCursorPosition, dwGlobalConsoleMode); + //} + } + ctr++; + Sleep(0); + } + + *dwWritten = len; + + //netflush(); + + return 0; +} + + diff --git a/contrib/win32/win32compat/console.c b/contrib/win32/win32compat/console.c new file mode 100644 index 000000000..9e2a71ca4 --- /dev/null +++ b/contrib/win32/win32compat/console.c @@ -0,0 +1,1590 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* console.c + * + * Common library for Windows Console Screen IO. + * Contains Windows console related definition so that emulation code can draw + * on Windows console screen surface. + * + */ + +#include +#include +#include +#include +#include "console.h" +#include + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 +#endif + +HANDLE hOutputConsole = NULL; +DWORD dwSavedAttributes = 0; +WORD wStartingAttributes = 0; + +int ScreenX; +int ScreenY; +int ScrollTop; +int ScrollBottom; +int LastCursorX; +int LastCursorY; + +char *pSavedScreen = NULL; +static COORD ZeroCoord = {0,0}; +COORD SavedScreenSize = {0,0}; +COORD SavedScreenCursor = {0, 0 }; +SMALL_RECT SavedViewRect = {0,0,0,0}; +CONSOLE_SCREEN_BUFFER_INFOEX SavedWindowState; + +typedef struct _SCREEN_RECORD{ + PCHAR_INFO pScreenBuf; + COORD ScreenSize; + COORD ScreenCursor; + SMALL_RECT srWindowRect; +}SCREEN_RECORD,*PSCREEN_RECORD; + +PSCREEN_RECORD pSavedScreenRec = NULL; + +/* ************************************************************ */ +/* Function: ConInit */ +/* Used to Initialize the Console for output */ +/* ************************************************************ */ +int ConInit( DWORD OutputHandle, BOOL fSmartInit ) +{ + OSVERSIONINFO os; + DWORD dwAttributes = 0; + DWORD dwRet = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + static bool bFirstConInit = true; + + os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + GetVersionEx( &os ); + + hOutputConsole = GetStdHandle(OutputHandle); + if (hOutputConsole == INVALID_HANDLE_VALUE) { + dwRet = GetLastError(); + printf("GetStdHandle failed with %d\n", dwRet); + return dwRet; + } + + if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) { + dwRet = GetLastError(); + printf("GetConsoleMode failed with %d\n", GetLastError()); + return dwRet; + } + + dwAttributes = dwSavedAttributes; + dwAttributes &= ~(ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); + dwAttributes |= ENABLE_WINDOW_INPUT; + + char *term = getenv("TERM"); + + if (term != NULL && (_stricmp(term, "ansi") == 0 || _stricmp(term, "passthru") == 0)) + dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes); // Windows NT + + ConSetScreenX(); + ConSetScreenY(); + ScrollTop = 0; + ScrollBottom = ConWindowSizeY(); + + if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) + SavedViewRect = csbi.srWindow; + + return 0; +} + + +/* ************************************************************ */ +/* Function: ConUnInit */ +/* Used to Uninitialize the Console */ +/* ************************************************************ */ +int ConUnInit( void ) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if ( hOutputConsole == NULL ) + return 0; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return 0; + + SetConsoleMode(hOutputConsole, dwSavedAttributes); + + return 0; +} + +/* ************************************************************ */ +/* Function: ConUnInit */ +/* Used to Uninitialize the Console */ +/* ************************************************************ */ +int ConUnInitWithRestore( void ) +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if ( hOutputConsole == NULL ) + return 0; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return 0; + + SetConsoleMode(hOutputConsole, dwSavedAttributes); + + Coord = ConsoleInfo.dwCursorPosition; + Coord.X = 0; + + DWORD dwNumChar = (ConsoleInfo.dwSize.Y - ConsoleInfo.dwCursorPosition.Y) * + ConsoleInfo.dwSize.X; + + FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, wStartingAttributes, dwNumChar, + Coord, &dwWritten); + + SetConsoleTextAttribute(hOutputConsole, wStartingAttributes); + + return 0; +} + +BOOL ConSetScreenRect( int xSize, int ySize ) +{ + BOOL bSuccess = TRUE; + + CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ + SMALL_RECT srWindowRect; /* hold the new console size */ + COORD coordScreen; + + bSuccess = GetConsoleScreenBufferInfo(hOutputConsole, &csbi); + if (!bSuccess) { + return bSuccess; + } + + /* get the largest size we can size the console window to */ + coordScreen = GetLargestConsoleWindowSize(hOutputConsole); + + /* define the new console window size and scroll position */ + srWindowRect.Top = csbi.srWindow.Top; + srWindowRect.Left = csbi.srWindow.Left; + srWindowRect.Right = xSize - 1 + srWindowRect.Left; + srWindowRect.Bottom = ySize - 1 + srWindowRect.Top; + + /* define the new console buffer size */ + coordScreen.X = max(csbi.dwSize.X, xSize); + coordScreen.Y = max(csbi.dwSize.Y, ySize); + + /* if the current buffer is larger than what we want, resize the */ + /* console window first, then the buffer */ + if (csbi.dwSize.X < coordScreen.X || + csbi.dwSize.Y < coordScreen.Y) + { + bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); + if (bSuccess) + bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); + } + else + { + bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); + if (bSuccess) + bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); + } + + if (bSuccess) + ConSaveViewRect(); + + /* if the current buffer *is* the size we want, don't do anything! */ + return bSuccess; +} + +BOOL ConSetScreenSize( int xSize, int ySize ) +{ + BOOL bSuccess = TRUE; + + CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ + SMALL_RECT srWindowRect; /* hold the new console size */ + COORD coordScreen; + + bSuccess = GetConsoleScreenBufferInfo(hOutputConsole, &csbi); + if (!bSuccess) { + return bSuccess; + } + + /* get the largest size we can size the console window to */ + coordScreen = GetLargestConsoleWindowSize(hOutputConsole); + + /* define the new console window size and scroll position */ + srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1); + srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1); + srWindowRect.Left = srWindowRect.Top = (SHORT) 0; + + /* define the new console buffer size */ + coordScreen.X = xSize; + coordScreen.Y = ySize; + + /* if the current buffer is larger than what we want, resize the */ + /* console window first, then the buffer */ + if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize) + { + bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); + if (bSuccess) + { + bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); + } + } + + /* if the current buffer is smaller than what we want, resize the */ + /* buffer first, then the console window */ + if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize) + { + bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); + if (bSuccess) + bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); + } + + if (bSuccess) + ConSaveViewRect(); + + /* if the current buffer *is* the size we want, don't do anything! */ + return bSuccess; +} + +/* ************************************************************ */ +/* Function: ConSetAttributes */ +/* Used to set the Color of the console and other attributes */ +/* ************************************************************ */ +void ConSetAttribute(int *iParam, int iParamCount) +{ + static int iAttr = 0; + int i = 0; + BOOL bRet = TRUE; + + if (iParamCount < 1) + { + iAttr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + + iAttr = iAttr & ~BACKGROUND_INTENSITY; + iAttr = iAttr & ~FOREGROUND_INTENSITY; + iAttr = iAttr & ~COMMON_LVB_UNDERSCORE; + iAttr = iAttr & ~COMMON_LVB_REVERSE_VIDEO; + + SetConsoleTextAttribute(hOutputConsole, (WORD)iAttr); + } + else + { + for (i=0;i ScrollBottom-1) + { + ConScrollDown( ScrollTop, ScrollBottom ); + ConSetCursorPosition( 0, ScrollBottom ); + } + else + ConSetCursorPosition( 0, Y ); + break; + + default: + + fOkay = (BOOL)WriteConsole( hOutputConsole, &ch, 1, (LPDWORD)&Result, 0 ); + + if ( X >= ScreenX-1 ) // last coord + { + if (Y >= ScrollBottom-1) // last coord + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + { + ConMoveCursorPosition(-ConGetCursorX(),1); + } + } + break; + } + + return fOkay; +} + + +BOOL ConWriteCharW(WCHAR ch) +{ + int X, Y, Result; + BOOL fOkay = TRUE; + + Y = ConGetCursorY(); + X = ConGetCursorX(); + + switch ( ch ) + { + case 0x8: // BackSpace + if ( X == 0 ) + { + ConSetCursorPosition( ScreenX - 1, --Y ); + WriteConsole( hOutputConsole, " ", 1, (LPDWORD)&Result, 0 ); + ConSetCursorPosition( ScreenX - 1, Y ); + } + else + { + ConSetCursorPosition( X - 1, Y ); + WriteConsole( hOutputConsole, " ", 1, (LPDWORD)&Result, 0 ); + ConSetCursorPosition( X - 1, Y ); + } + + break; + case L'\r': + ConSetCursorPosition( 0, Y ); + break; + + case L'\n': + Y++; + if ( Y > ScrollBottom-1) + { + ConScrollDown( ScrollTop, ScrollBottom ); + ConSetCursorPosition( 0, ScrollBottom ); + } + else + ConSetCursorPosition( 0, Y ); + break; + + default: + fOkay = (BOOL)WriteConsoleW( hOutputConsole, &ch, 1, (LPDWORD)&Result, 0 ); + + if ( X >= ScreenX-1 ) // last coord + { + if (Y >= ScrollBottom-1) // last coord + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + { + ConMoveCursorPosition(-ConGetCursorX(),1); + } + } + break; + } + + return fOkay; +} + + +/* Special Function for handling TABS and other bad control chars */ +int ConWriteConsole( char *pData, int NumChars ) +{ + int X, CurrentY, CurrentX, Result; + + for( X = 0; (X < NumChars) && (pData[X] != '\0') ; X++ ) + { + switch (pData[X]) + { + + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 11: + break; + + case 7: + Beep( 1000, 400); + break; + + case 8: + ConMoveCursorPosition( -1, 0 ); + WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); + ConMoveCursorPosition( -1, 0 ); + break; + + case 9: + { + int i, MoveRight = TAB_LENGTH - (ConGetCursorX() % TAB_LENGTH); + + for ( i = 0; i < MoveRight; i++ ) + WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); + } + break; + + case 10: + CurrentY = ConGetCursorY()+1; + if (CurrentY >= ScrollBottom) + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + { + ConMoveCursorPosition(0,1); + } + break; + + case 12: + ConClearScreen(); + ConSetCursorPosition(0, 0); + break; + + case 13: + ConMoveCursorPosition(-ConGetCursorX(),0); + break; + + case 14: + break; + + case 15: + break; + + default: + { + + CurrentY = ConGetCursorY(); + CurrentX = ConGetCursorX(); + + WriteConsole(hOutputConsole, &pData[X], 1, (LPDWORD)&Result, 0); + + if ( CurrentX >= ScreenX-1) // last coord + { + if (CurrentY >= ScrollBottom-1) // last coord + { + ConScrollDown(ScrollTop,ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(),0); + } + else + { + ConMoveCursorPosition(-ConGetCursorX(),1); + } + } + } + } + } + + return X; +} + +PCHAR ConWriteLine(char* pData) +{ + PCHAR pCurrent, pNext, pTab; + DWORD Result; + size_t distance, tabCount, pos; + size_t tabLength, charCount; + + pCurrent = pData; + + pNext = strchr( pCurrent, '\r' ); + if ( pNext != NULL ) + { + distance = pNext - pCurrent; + + if ( distance > (size_t)ScreenX ) + distance = (size_t)ScreenX; + + pos = 0; + tabCount = 0; + pTab = strchr( pCurrent, TAB_CHAR ); + if ( (pTab != NULL) && (pTab < pNext) ) + { + // Tab exists in string + // So we use our WriteString + while ( (pTab != NULL) && (pTab < pNext) && (pos < (size_t)ScreenX) ) + { + tabCount++; + charCount = (pTab - pCurrent) - 1; // Ignore actual TAB since we add 8 for it + pos = charCount + (tabCount * TAB_LENGTH); + pTab++; // increment past last tab + pTab = strchr( pTab, TAB_CHAR ); + } + + tabLength = (tabCount * TAB_LENGTH); + +// if ( pos >= ScreenX ) + distance = ConWriteConsole( pCurrent, (int)distance );// Special routine for handling TABS + + } + else + WriteConsole( hOutputConsole,pCurrent, (DWORD)distance, &Result, 0 ); + + ConSetCursorPosition( 0, ConGetCursorY() + 1 ); + + pCurrent+= (distance + 2); // Add one to always skip last char printed + } + else + { + distance = strlen( pCurrent ); + if ( distance > (size_t)ScreenX ) + distance = (size_t)ScreenX; + WriteConsole( hOutputConsole, pCurrent, (DWORD)distance, &Result, 0 ); + pCurrent += distance; + } + + return pCurrent; +} + +PCHAR ConDisplayData(char* pData, int NumLines) +{ + PCHAR pCurrent, pNext, pTab; + DWORD Result; + size_t Y, distance, pos, add; + int linecnt = 0; + + pCurrent = pData; + + for ( ;(pCurrent) && + ((Y = (size_t)ConGetCursorY()) <= (size_t)ScrollBottom) && + (*pCurrent != '\0'); ) + { + pNext = strchr( pCurrent, '\n' ); + if ( pNext != NULL ) + { + --pNext; + if ( *pNext != '\r' ) + { + pNext++; + add = 1; + } + else + add = 2; + distance = pNext - pCurrent; + + if ( distance > 0 && linecnt < NumLines) + { + pos = 0; + pTab = strchr( pCurrent, TAB_CHAR ); + if ( (distance > (size_t)ScreenX) || ((pTab != NULL) && (pTab < pNext)) ) + { + ConWriteConsole( pCurrent, (int)distance ); // Special routine for handling TABS + } + else + { + WriteConsole( hOutputConsole, pCurrent, (DWORD)distance, &Result, 0 ); + } + } + ConMoveCursorPosition(-ConGetCursorX(),1); + pCurrent += (distance + add); // Add one to always skip last char printed + linecnt++; + } + else + { + distance = strlen( pCurrent ); + if ( distance > (size_t)ScreenX ) + distance = ScreenX; + if (linecnt < NumLines) + WriteConsole( hOutputConsole, pCurrent, (DWORD)distance, &Result, 0 ); + return pCurrent + distance; + } + } + return pCurrent; +} + +int Con_printf( const char *Format, ... ) +{ + va_list va_data; + int len; + char Temp[4096]; + + memset( Temp, '\0', sizeof( Temp ) ); + + va_start( va_data, Format ); + + len = vsnprintf( Temp, sizeof(Temp), Format, va_data ); + + ConWriteConsole(Temp, len); + + va_end( va_data ); + + return len; +} + +BOOL ConDisplayCursor( BOOL bVisible ) +{ + CONSOLE_CURSOR_INFO ConsoleCursorInfo; + + if (GetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo)) { + + ConsoleCursorInfo.bVisible = bVisible; + + return SetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo); + } + + return FALSE; +} + +void ConClearScreen(void) +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + SMALL_RECT srcWindow; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = 0; + + DWORD dwNumChar = (ConsoleInfo.srWindow.Bottom + 1) * + (ConsoleInfo.srWindow.Right + 1); + + FillConsoleOutputCharacter(hOutputConsole, ' ', + dwNumChar, + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + dwNumChar, + Coord, &dwWritten); + + srcWindow = ConsoleInfo.srWindow; + + ConSetCursorPosition(0, 0); +} + +void ConClearScrollRegion() +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = ScrollTop+ConsoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)ConsoleInfo.dwSize.X * (DWORD)ScrollBottom, + Coord, &dwWritten); + + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)ConsoleInfo.dwSize.X * (DWORD)ScrollBottom, + Coord, &dwWritten); + + ConSetCursorPosition( 0, ScrollTop ); +} + +void ConClearEOScreen() +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = (short)(ConGetCursorY() + 1) + ConsoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)(ConsoleInfo.dwSize.X)* + (DWORD)(ConsoleInfo.srWindow.Bottom - Coord.Y + 1), + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)(ConsoleInfo.dwSize.X)* + (DWORD)(ConsoleInfo.srWindow.Bottom - Coord.Y + 1), + Coord, &dwWritten); + + ConClearEOLine(); +} + +void ConClearBOScreen() +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = 0; + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)(ConsoleInfo.dwSize.X)* + (DWORD)(ConsoleInfo.dwSize.Y - ConGetCursorY() - 1), + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)(ConsoleInfo.dwSize.X)* + (DWORD)(ConsoleInfo.dwSize.Y - ConGetCursorY() - 1), + Coord, &dwWritten); + + ConClearBOLine(); +} + +void ConClearLine() +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = ConGetCursorY(); + + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, ScreenX, + Coord, &dwWritten); + FillConsoleOutputCharacter(hOutputConsole, ' ',ScreenX, + Coord, &dwWritten); +} + +void ConClearEOLine() +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return;; + + Coord.X = ConGetCursorX()+ConsoleInfo.srWindow.Left; + Coord.Y = ConGetCursorY()+ConsoleInfo.srWindow.Top; + + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)(ScreenX - ConGetCursorX()), + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)(ScreenX - ConGetCursorX()), + Coord, &dwWritten); +} + +void ConClearNFromCursorRight(int n) +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + + Coord.X = ConGetCursorX()+ConsoleInfo.srWindow.Left; + Coord.Y = ConGetCursorY()+ConsoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)n, + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)n, + Coord, &dwWritten); +} + +void ConClearNFromCursorLeft(int n) +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = ConGetCursorX()+ConsoleInfo.srWindow.Left-n; + Coord.Y = ConGetCursorY()+ConsoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)n, + Coord, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)n, + Coord, &dwWritten); +} + +void ConScrollDownEntireBuffer() +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + ConScrollDown(0, ConsoleInfo.dwSize.Y - 1); + return; +} + +void ConScrollUpEntireBuffer() +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + ConScrollUp(0, ConsoleInfo.dwSize.Y - 1); + return; +} + +void ConScrollUp(int topline,int botline) +{ + SMALL_RECT ScrollRect; + SMALL_RECT ClipRect; + COORD destination; + CHAR_INFO Fill; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + if ((botline - topline) == ConsoleInfo.dwSize.Y-1) // scrolling whole buffer + { + ScrollRect.Top = topline; + ScrollRect.Bottom = botline; + } + else + { + ScrollRect.Top = topline + ConsoleInfo.srWindow.Top; + ScrollRect.Bottom = botline + ConsoleInfo.srWindow.Top; + } + ScrollRect.Left = 0; + ScrollRect.Right = ConScreenSizeX() -1; + + ClipRect.Top = ScrollRect.Top; + ClipRect.Bottom = ScrollRect.Bottom; + ClipRect.Left = ScrollRect.Left; + ClipRect.Right = ScrollRect.Right; + + destination.X = 0; + destination.Y = ScrollRect.Top+1; + + Fill.Attributes = ConsoleInfo.wAttributes; + Fill.Char.AsciiChar = ' '; + + BOOL bRet = ScrollConsoleScreenBuffer( hOutputConsole, + &ScrollRect, + &ClipRect, + destination, + &Fill + ); +} + +void ConScrollDown(int topline, int botline) +{ + SMALL_RECT ScrollRect; + SMALL_RECT ClipRect; + COORD destination; + CHAR_INFO Fill; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + if ((botline - topline) == ConsoleInfo.dwSize.Y - 1) // scrolling whole buffer + { + ScrollRect.Top = topline; + ScrollRect.Bottom = botline; + } + else + { + ScrollRect.Top = topline + ConsoleInfo.srWindow.Top + 1; + ScrollRect.Bottom = botline + ConsoleInfo.srWindow.Top; + } + + ScrollRect.Left = 0; + ScrollRect.Right = ConScreenSizeX() - 1; + + ClipRect.Top = ScrollRect.Top; + ClipRect.Bottom = ScrollRect.Bottom; + ClipRect.Left = ScrollRect.Left; + ClipRect.Right = ScrollRect.Right; + + destination.X = 0; + destination.Y = ScrollRect.Top - 1; + + Fill.Attributes = ConsoleInfo.wAttributes; + Fill.Char.AsciiChar = ' '; + + BOOL bRet = ScrollConsoleScreenBuffer( hOutputConsole, + &ScrollRect, + NULL, + destination, + &Fill + ); +} + +void ConClearBOLine() +{ + DWORD dwWritten; + COORD Coord ; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = 0; + Coord.Y = (short)(ConGetCursorY()); + FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, + (DWORD)(ConGetCursorX()), + Coord, &dwWritten); + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)(ConGetCursorX()), + Coord, &dwWritten); +} + +void ConSetCursorPosition(int x, int y) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + COORD Coord; + int rc; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = (short)(x); + Coord.Y = (short)(y); + + if ((y > ConsoleInfo.dwSize.Y - 1) && y > LastCursorY) { + for(int n = LastCursorY; n < y; n++) + GoToNextLine(); + } + + if (y >= ConsoleInfo.dwSize.Y) { + Coord.Y = ConsoleInfo.dwSize.Y - 1; + } + + if (!SetConsoleCursorPosition(hOutputConsole, Coord)) + rc = GetLastError(); + + LastCursorX = x; + LastCursorY = y; +} + +BOOL ConChangeCursor( CONSOLE_CURSOR_INFO *pCursorInfo ) +{ + return SetConsoleCursorInfo( hOutputConsole, pCursorInfo ); +} + +int ConGetCursorX() +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return 0; + + return ConsoleInfo.dwCursorPosition.X; +} + +int ConGetCursorY() +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + { + return 0; + } + + return (ConsoleInfo.dwCursorPosition.Y - ConsoleInfo.srWindow.Top); +} + +int ConGetCursorInBufferY() +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + { + return 0; + } + + return (ConsoleInfo.dwCursorPosition.Y); +} + +void ConMoveCursorPosition(int x, int y) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + COORD Coord; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = (short)(ConsoleInfo.dwCursorPosition.X + x); + Coord.Y = (short)(ConsoleInfo.dwCursorPosition.Y + y); + + SetConsoleCursorPosition(hOutputConsole, Coord); +} + +void ConGetRelativeCursorPosition(int *x, int *y) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + *x -= ConsoleInfo.srWindow.Left; + *y -= ConsoleInfo.srWindow.Top; +} + +void ConDeleteChars(int n) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + COORD Coord; + CHAR_INFO chiBuffer[256]; // 1 row, 256 characters + SMALL_RECT sr; + COORD Temp; + int result; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return; + + Coord.X = (short)(ConsoleInfo.dwCursorPosition.X); + Coord.Y = (short)(ConsoleInfo.dwCursorPosition.Y); + + sr.Left = Coord.X + n; + sr.Top = Coord.Y; + sr.Bottom = Coord.Y; + sr.Right = ConsoleInfo.srWindow.Right; + + Temp.X = 256; + Temp.Y = 1; + result = ReadConsoleOutput( hOutputConsole, // handle of a console screen buffer + (PCHAR_INFO)chiBuffer, // address of buffer that receives data + Temp, // column-row size of destination buffer + ZeroCoord, // upper-left cell to write to + &sr // address of rectangle to read from + ); + ConClearEOLine(); + + sr.Left = Coord.X; + Temp.X = 256; + Temp.Y = 1; + + sr.Right -= n; + result = WriteConsoleOutput(hOutputConsole,(PCHAR_INFO)chiBuffer,Temp, ZeroCoord, &sr); +} + + +SCREEN_HANDLE ConSaveScreenHandle( SCREEN_HANDLE hScreen ) +{ + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + + PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; + + int result, width,height; + + if ( hOutputConsole == NULL ) + return NULL; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return (NULL); + + if (pScreenRec == NULL){ + pScreenRec = (PSCREEN_RECORD)malloc(sizeof(SCREEN_RECORD)); + pScreenRec->pScreenBuf = NULL; + } + + pScreenRec->srWindowRect = ConsoleInfo.srWindow; + width = ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1; + height = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1; + pScreenRec->ScreenSize.X = width; + pScreenRec->ScreenSize.Y = height; + pScreenRec->ScreenCursor.X = ConsoleInfo.dwCursorPosition.X-ConsoleInfo.srWindow.Left; + pScreenRec->ScreenCursor.Y = ConsoleInfo.dwCursorPosition.Y-ConsoleInfo.srWindow.Top; + + if (pScreenRec->pScreenBuf == NULL){ + pScreenRec->pScreenBuf = (PCHAR_INFO)malloc( sizeof(CHAR_INFO) * width * height ); + } + + if ( !pScreenRec->pScreenBuf ) + { + if ( pScreenRec != (PSCREEN_RECORD)hScreen ) { + free(pScreenRec); + } + return NULL; + } + + result = ReadConsoleOutput( hOutputConsole, // handle of a console screen buffer + (PCHAR_INFO)(pScreenRec->pScreenBuf), // address of buffer that receives data + pScreenRec->ScreenSize, // column-row size of destination buffer + ZeroCoord, // upper-left cell to write to + &ConsoleInfo.srWindow // address of rectangle to read from + ); + + return((SCREEN_HANDLE)pScreenRec); +} + + +BOOL ConRestoreScreenHandle( SCREEN_HANDLE hScreen ) +{ + BOOL fOkay = FALSE; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + COORD beginOfScreen = { 0, 0 }; + PCHAR_INFO pSavedCharInfo; + DWORD dwWritten; + PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; + int width, height; + + if ( hOutputConsole == NULL ) + return FALSE; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return (FALSE); + + width = ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1; + height = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1; + + beginOfScreen.X = ConsoleInfo.srWindow.Left; + beginOfScreen.Y = ConsoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)width*height, + beginOfScreen, &dwWritten); + + pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); + SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); + + FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, + (DWORD)width*height, + beginOfScreen, &dwWritten); + + fOkay = WriteConsoleOutput( hOutputConsole, // handle to a console screen buffer + (PCHAR_INFO)(pScreenRec->pScreenBuf), // pointer to buffer with data to write + pScreenRec->ScreenSize, // column-row size of source buffer + ZeroCoord, // upper-left cell to write from + &ConsoleInfo.srWindow // pointer to rectangle to write to + ); + + SetConsoleWindowInfo(hOutputConsole,TRUE,&pScreenRec->srWindowRect); + + ConSetCursorPosition( pScreenRec->ScreenCursor.X, pScreenRec->ScreenCursor.Y ); + + return fOkay; +} + +BOOL ConRestoreScreenColors( ) +{ + SCREEN_HANDLE hScreen = pSavedScreenRec; + BOOL fOkay = FALSE; + CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + COORD beginOfScreen = { 0, 0 }; + PCHAR_INFO pSavedCharInfo; + DWORD dwWritten; + PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; + + if ( hOutputConsole == NULL ) + return FALSE; + + if ( pSavedScreen == NULL ) + return FALSE; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) + return (FALSE); + + beginOfScreen.X = ConsoleInfo.srWindow.Left; + beginOfScreen.Y = ConsoleInfo.srWindow.Top; + + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, + beginOfScreen, &dwWritten); + + pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); + SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); + + FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, + (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, + beginOfScreen, &dwWritten); + + return fOkay; +} + +void ConDeleteScreenHandle( SCREEN_HANDLE hScreen ) +{ + PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; + + free(pScreenRec->pScreenBuf); + free(pScreenRec); + +} + +/* ************************************************************ */ +/* Function: ConRestoreScreen */ +/* Restores Previous Saved screen info and buffer */ +/* ************************************************************ */ +BOOL ConRestoreScreen( void ) +{ + return ConRestoreScreenHandle(pSavedScreenRec); +} + +void ConRestoreViewRect( void ) +{ + //SetConsoleWindowInfo(hOutputConsole,TRUE,&SavedViewRect); +} + +/* ************************************************************ */ +/* Function: ConSaveScreen */ +/* Saves current screen info and buffer */ +/* ************************************************************ */ +BOOL ConSaveScreen( void ) +{ + pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec); + return TRUE; +} + +void ConSaveViewRect( void ) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) + return; + + SavedViewRect = csbi.srWindow; + +} + +BOOL ConIsRedirected(HANDLE hInput) +{ + DWORD dwMode; + + return !GetConsoleMode(hInput, &dwMode); +} + +HANDLE GetConsoleOutputHandle() +{ + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE); + + if (ConIsRedirected(hTemp)) + { + hTemp = CreateFile(TEXT("CONOUT$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); + } + + return hTemp; +} + +HANDLE GetConsoleInputHandle() +{ + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + HANDLE hTemp = GetStdHandle(STD_INPUT_HANDLE); + + if (ConIsRedirected(hTemp)) + { + hTemp = CreateFile(TEXT("CONIN$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); + } + + return hTemp; +} + +void ConSaveWindowsState(void) +{ + CONSOLE_SCREEN_BUFFER_INFOEX csbiex; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + + if (!GetConsoleScreenBufferInfoEx(hOutputConsole, &csbiex)) + return; + + SavedWindowState = csbiex; +} diff --git a/contrib/win32/win32compat/console.h b/contrib/win32/win32compat/console.h new file mode 100644 index 000000000..f06143e26 --- /dev/null +++ b/contrib/win32/win32compat/console.h @@ -0,0 +1,139 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* console.h + * + * Common library for Windows Console Screen IO. + * Contains Windows console related definition so that emulation code can draw + * on Windows console screen surface. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + */ + +#ifndef __PRAGMA_CONSOLE_h +#define __PRAGMA_CONSOLE_h + +#define ANSI_ATTR_RESET 0 +#define ANSI_BRIGHT 1 +#define ANSI_DIM 2 +#define ANSI_UNDERSCORE 4 +#define ANSI_BLINK 5 +#define ANSI_REVERSE 7 +#define ANSI_HIDDEN 8 +#define ANSI_NOUNDERSCORE 24 +#define ANSI_NOREVERSE 27 + +#define ANSI_FOREGROUND_BLACK 30 +#define ANSI_FOREGROUND_RED 31 +#define ANSI_FOREGROUND_GREEN 32 +#define ANSI_FOREGROUND_YELLOW 33 +#define ANSI_FOREGROUND_BLUE 34 +#define ANSI_FOREGROUND_MAGENTA 35 +#define ANSI_FOREGROUND_CYAN 36 +#define ANSI_FOREGROUND_WHITE 37 +#define ANSI_DEFAULT_FOREGROUND 39 +#define ANSI_BACKGROUND_BLACK 40 +#define ANSI_BACKGROUND_RED 41 +#define ANSI_BACKGROUND_GREEN 42 +#define ANSI_BACKGROUND_YELLOW 43 +#define ANSI_BACKGROUND_BLUE 44 +#define ANSI_BACKGROUND_MAGENTA 45 +#define ANSI_BACKGROUND_CYAN 46 +#define ANSI_BACKGROUND_WHITE 47 +#define ANSI_DEFAULT_BACKGROUND 49 +#define ANSI_BACKGROUND_BRIGHT 128 + +#define TAB_LENGTH 4 +#define TAB_CHAR '\t' +#define TAB_SPACE " " + +#define true TRUE +#define false FALSE +#define bool BOOL + +typedef void * SCREEN_HANDLE; + +int ConInit( DWORD OutputHandle, BOOL fSmartInit); +int ConUnInitWithRestore( void ); +int ConUnInit( void ); +BOOL ConIsRedirected(HANDLE hInput); +HANDLE GetConsoleOutputHandle(); +HANDLE GetConsoleInputHandle(); +BOOL ConSetScreenRect( int xSize, int ySize ); +BOOL ConSetScreenSize( int X, int Y ); +BOOL ConRestoreScreen( void ); +BOOL ConSaveScreen( void ); +void ConSetAttribute( int *iParam, int iParamCount ); +int ConScreenSizeX(); +int ConSetScreenX(); +int ConScreenSizeY(); +int ConWindowSizeX(); +int ConWindowSizeY(); +int ConSetScreenY(); +void ConFillToEndOfLine(); +int ConWriteString(char* pszString, int cbString); +BOOL ConWriteChar( CHAR ch ); +int ConWriteConsole( char *pData, int NumChars ); +PCHAR ConDisplayData(char* pData, int NumLines); +PCHAR ConWriteLine(char* pData); +int Con_printf( const char *Format, ... ); +void ConClearScrollRegion(); +void ConClearScreen(); +void ConClearEOScreen(); +void ConClearBOScreen(); +void ConClearLine(); +void ConClearEOLine(); +void ConClearNFromCursorRight(int n); +void ConClearNFromCursorLeft(int n); +void ConScrollUpEntireBuffer(); +void ConScrollDownEntireBuffer(); +void ConScrollUp(int topline,int botline); +void ConScrollDown(int topline,int botline); +void ConClearBOLine(); +BOOL ConChangeCursor( CONSOLE_CURSOR_INFO *pCursorInfo ); +void ConSetCursorPosition(int x, int y); +int ConGetCursorX(); +int ConGetCursorY(); +int ConGetCursorInBufferY(void); +BOOL ConDisplayCursor( BOOL bVisible ); +void ConMoveCursorPosition(int x, int y); +void ConGetRelativeCursorPosition(int *x, int *y); +BOOL ConRestoreScreenHandle( SCREEN_HANDLE hScreen ); +BOOL ConRestoreScreenColors( void ); +SCREEN_HANDLE ConSaveScreenHandle( SCREEN_HANDLE); +void ConDeleteScreenHandle( SCREEN_HANDLE hScreen ); +void ConSaveViewRect( void ); +void ConRestoreViewRect( void ); +void ConDeleteChars(int n); +void ConSaveWindowsState(void); + + +#endif diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c new file mode 100644 index 000000000..8d7ed26d5 --- /dev/null +++ b/contrib/win32/win32compat/fileio.c @@ -0,0 +1,694 @@ +/* +* Author: Manoj Ampalam +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 "w32fd.h" +#include "inc/defs.h" +#include +#include +#include "inc\utf.h" + +/* internal read buffer size */ +#define READ_BUFFER_SIZE 100*1024 +/* internal write buffer size */ +#define WRITE_BUFFER_SIZE 100*1024 +#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError()) + +int termio_initiate_read(struct w32_io* pio); +int termio_initiate_write(struct w32_io* pio, DWORD num_bytes); + +/* maps Win32 error to errno */ +int +errno_from_Win32Error(int win32_error) +{ + switch (win32_error) { + case ERROR_ACCESS_DENIED: + return EACCES; + case ERROR_OUTOFMEMORY: + return ENOMEM; + case ERROR_FILE_EXISTS: + return EEXIST; + case ERROR_FILE_NOT_FOUND: + return ENOENT; + default: + return win32_error; + } +} + +/* used to name named pipes used to implement pipe() */ +static int pipe_counter = 0; + +/* + * pipe() implementation. Creates an inbound named pipe, uses CreateFile to connect + * to it. These handles are associated with read end and write end of the pipe + */ +int +fileio_pipe(struct w32_io* pio[2]) { + HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE; + struct w32_io *pio_read = NULL, *pio_write = NULL; + char pipe_name[MAX_PATH]; + SECURITY_ATTRIBUTES sec_attributes; + + if (pio == NULL) { + errno = EINVAL; + debug("pipe - ERROR invalid parameter"); + return -1; + } + + /* create name for named pipe */ + if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", + GetCurrentProcessId(), pipe_counter++)) { + errno = EOTHER; + debug("pipe - ERROR sprintf_s %d", errno); + goto error; + } + + sec_attributes.bInheritHandle = TRUE; + sec_attributes.lpSecurityDescriptor = NULL; + sec_attributes.nLength = 0; + + /* create named pipe */ + read_handle = CreateNamedPipeA(pipe_name, + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_WAIT, + 1, + 4096, + 4096, + 0, + &sec_attributes); + if (read_handle == INVALID_HANDLE_VALUE) { + errno = errno_from_Win32LastError(); + debug("pipe - CreateNamedPipe() ERROR:%d", errno); + goto error; + } + + /* connect to named pipe */ + write_handle = CreateFileA(pipe_name, + GENERIC_WRITE, + 0, + &sec_attributes, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + if (write_handle == INVALID_HANDLE_VALUE) { + errno = errno_from_Win32LastError(); + debug("pipe - ERROR CreateFile() :%d", errno); + goto error; + } + + /* create w32_io objects encapsulating above handles */ + pio_read = (struct w32_io*)malloc(sizeof(struct w32_io)); + pio_write = (struct w32_io*)malloc(sizeof(struct w32_io)); + + if (!pio_read || !pio_write) { + errno = ENOMEM; + debug("pip - ERROR:%d", errno); + goto error; + } + + memset(pio_read, 0, sizeof(struct w32_io)); + memset(pio_write, 0, sizeof(struct w32_io)); + + pio_read->handle = read_handle; + pio_write->handle = write_handle; + + pio[0] = pio_read; + pio[1] = pio_write; + return 0; + +error: + if (read_handle) + CloseHandle(read_handle); + if (write_handle) + CloseHandle(write_handle); + if (pio_read) + free(pio_read); + if (pio_write) + free(pio_write); + return -1; +} + +struct createFile_flags { + DWORD dwDesiredAccess; + DWORD dwShareMode; + SECURITY_ATTRIBUTES securityAttributes; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; +}; + +/* maps open() file modes and flags to ones needed by CreateFile */ +static int +createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { + + /* check flags */ + int rwflags = flags & 0x3; + int c_s_flags = flags & 0xfffffff0; + + /* + * should be one of one of the following access modes: + * O_RDONLY, O_WRONLY, or O_RDWR + */ + if ((rwflags != O_RDONLY) && (rwflags != O_WRONLY) && (rwflags != O_RDWR)) { + debug("open - flags ERROR: wrong rw flags: %d", flags); + errno = EINVAL; + return -1; + } + + /*only following create and status flags currently supported*/ + if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC + | O_EXCL | O_BINARY)) { + debug("open - ERROR: Unsupported flags: %d", flags); + errno = ENOTSUP; + return -1; + } + + /*validate mode*/ + if (mode &~(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { + debug("open - ERROR: unsupported mode: %d", mode); + errno = ENOTSUP; + return -1; + } + + cf_flags->dwShareMode = 0; + + switch (rwflags) { + case O_RDONLY: + cf_flags->dwDesiredAccess = GENERIC_READ; + /*todo: need to review to make sure all flags are correct*/ + if (flags & O_NONBLOCK) + cf_flags->dwShareMode = FILE_SHARE_READ; + break; + case O_WRONLY: + cf_flags->dwDesiredAccess = GENERIC_WRITE; + break; + case O_RDWR: + cf_flags->dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + break; + } + + cf_flags->securityAttributes.lpSecurityDescriptor = NULL; + cf_flags->securityAttributes.bInheritHandle = TRUE; + cf_flags->securityAttributes.nLength = 0; + + cf_flags->dwCreationDisposition = OPEN_EXISTING; + if (c_s_flags & O_TRUNC) + cf_flags->dwCreationDisposition = TRUNCATE_EXISTING; + if (c_s_flags & O_CREAT) { + if (c_s_flags & O_EXCL) + cf_flags->dwCreationDisposition = CREATE_NEW; + else + cf_flags->dwCreationDisposition = CREATE_ALWAYS; + } + + if (c_s_flags & O_APPEND) + cf_flags->dwDesiredAccess = FILE_APPEND_DATA; + + cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | SECURITY_IMPERSONATION | FILE_FLAG_BACKUP_SEMANTICS; + + /*TODO - map mode */ + + return 0; +} + +/* open() implementation. Uses CreateFile to open file, console, device, etc */ +struct w32_io* + fileio_open(const char *path_utf8, int flags, int mode) { + struct w32_io* pio = NULL; + struct createFile_flags cf_flags; + HANDLE handle; + wchar_t *path_utf16 = NULL; + + debug2("open - pathname:%s, flags:%d, mode:%d", path_utf8, flags, mode); + /* check input params*/ + if (path_utf8 == NULL) { + errno = EINVAL; + debug("open - ERROR:%d", errno); + return NULL; + } + + if ((path_utf16 = utf8_to_utf16(path_utf8)) == NULL) { + errno = ENOMEM; + debug("utf8_to_utf16 failed - ERROR:%d", GetLastError()); + return NULL; + } + + if (createFile_flags_setup(flags, mode, &cf_flags) == -1) + return NULL; + + handle = CreateFileW(path_utf16, cf_flags.dwDesiredAccess, cf_flags.dwShareMode, + &cf_flags.securityAttributes, cf_flags.dwCreationDisposition, + cf_flags.dwFlagsAndAttributes, NULL); + + if (handle == INVALID_HANDLE_VALUE) { + errno = errno_from_Win32LastError(); + debug("open - CreateFile ERROR:%d", GetLastError()); + free(path_utf16); + return NULL; + } + + free(path_utf16); + pio = (struct w32_io*)malloc(sizeof(struct w32_io)); + if (pio == NULL) { + CloseHandle(handle); + errno = ENOMEM; + debug("open - ERROR:%d", errno); + return NULL; + } + + memset(pio, 0, sizeof(struct w32_io)); + + if (flags & O_NONBLOCK) + pio->fd_status_flags = O_NONBLOCK; + + pio->handle = handle; + return pio; +} + +VOID CALLBACK ReadCompletionRoutine( + _In_ DWORD dwErrorCode, + _In_ DWORD dwNumberOfBytesTransfered, + _Inout_ LPOVERLAPPED lpOverlapped + ) { + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); + debug2("ReadCB pio:%p, pending_state:%d, error:%d, received:%d", + pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered); + pio->read_details.error = dwErrorCode; + pio->read_details.remaining = dwNumberOfBytesTransfered; + pio->read_details.completed = 0; + pio->read_details.pending = FALSE; + *((__int64*)&lpOverlapped->Offset) += dwNumberOfBytesTransfered; +} + +/* initiate an async read */ +/* TODO: make this a void func, store error in context */ +int +fileio_ReadFileEx(struct w32_io* pio, unsigned int bytes_requested) { + debug2("ReadFileEx io:%p", pio); + + if (pio->read_details.buf == NULL) { + pio->read_details.buf = malloc(READ_BUFFER_SIZE); + if (!pio->read_details.buf) { + errno = ENOMEM; + debug2("ReadFileEx - ERROR: %d, io:%p", errno, pio); + return -1; + } + } + + if (FILETYPE(pio) == FILE_TYPE_DISK) + pio->read_details.buf_size = min(bytes_requested, READ_BUFFER_SIZE); + else + pio->read_details.buf_size = READ_BUFFER_SIZE; + + if (ReadFileEx(WINHANDLE(pio), pio->read_details.buf, pio->read_details.buf_size, + &pio->read_overlapped, &ReadCompletionRoutine)) + pio->read_details.pending = TRUE; + else { + errno = errno_from_Win32LastError(); + debug("ReadFileEx() ERROR:%d, io:%p", GetLastError(), pio); + return -1; + } + + return 0; +} + +/* read() implementation */ +int +fileio_read(struct w32_io* pio, void *dst, unsigned int max) { + int bytes_copied; + + debug3("read - io:%p remaining:%d", pio, pio->read_details.remaining); + + /* if read is pending */ + if (pio->read_details.pending) { + if (w32_io_is_blocking(pio)) { + debug2("read - io is pending, blocking call made, io:%p", pio); + while (fileio_is_io_available(pio, TRUE) == FALSE) { + if (-1 == wait_for_any_event(NULL, 0, INFINITE)) + return -1; + } + } + errno = EAGAIN; + debug2("read - io is already pending, io:%p", pio); + return -1; + } + + if (fileio_is_io_available(pio, TRUE) == FALSE) { + if (FILETYPE(pio) == FILE_TYPE_CHAR) { + if (-1 == termio_initiate_read(pio)) + return -1; + } + else { + if (-1 == fileio_ReadFileEx(pio, max)) { + if ((FILETYPE(pio) == FILE_TYPE_PIPE) + && (errno == ERROR_BROKEN_PIPE)) { + /* write end of the pipe closed */ + debug("read - no more data, io:%p", pio); + errno = 0; + return 0; + } + /* on W2012, ReadFileEx on file throws a synchronous EOF error*/ + else if ((FILETYPE(pio) == FILE_TYPE_DISK) + && (errno == ERROR_HANDLE_EOF)) { + debug("read - no more data, io:%p", pio); + errno = 0; + return 0; + } + return -1; + } + } + + /* pick up APC if IO has completed */ + SleepEx(0, TRUE); + + if (w32_io_is_blocking(pio)) { + while (fileio_is_io_available(pio, TRUE) == FALSE) { + if (-1 == wait_for_any_event(NULL, 0, INFINITE)) + return -1; + } + } + else if (pio->read_details.pending) { + errno = EAGAIN; + debug2("read - IO is pending, io:%p", pio); + return -1; + } + } + + if (pio->read_details.error) { + errno = errno_from_Win32Error(pio->read_details.error); + /*write end of the pipe is closed or pipe broken or eof reached*/ + if ((pio->read_details.error == ERROR_BROKEN_PIPE) || + (pio->read_details.error == ERROR_HANDLE_EOF)) { + debug2("read - (2) no more data, io:%p", pio); + errno = 0; + pio->read_details.error = 0; + return 0; + } + debug("read - ERROR from cb :%d, io:%p", errno, pio); + pio->read_details.error = 0; + return -1; + } + + bytes_copied = min(max, pio->read_details.remaining); + memcpy(dst, pio->read_details.buf + pio->read_details.completed, bytes_copied); + pio->read_details.remaining -= bytes_copied; + pio->read_details.completed += bytes_copied; + debug2("read - io:%p read: %d remaining: %d", pio, bytes_copied, + pio->read_details.remaining); + return bytes_copied; +} + +VOID CALLBACK WriteCompletionRoutine( + _In_ DWORD dwErrorCode, + _In_ DWORD dwNumberOfBytesTransfered, + _Inout_ LPOVERLAPPED lpOverlapped + ) { + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); + debug2("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d", + pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered, + pio->write_details.remaining); + pio->write_details.error = dwErrorCode; + /* TODO - assert that remaining == dwNumberOfBytesTransfered */ + if ((dwErrorCode == 0) && (pio->write_details.remaining != dwNumberOfBytesTransfered)) { + debug("WriteCB - ERROR: broken assumption, io:%p, wrote:%d, remaining:%d", pio, + dwNumberOfBytesTransfered, pio->write_details.remaining); + DebugBreak(); + } + pio->write_details.remaining -= dwNumberOfBytesTransfered; + pio->write_details.pending = FALSE; + *((__int64*)&lpOverlapped->Offset) += dwNumberOfBytesTransfered; +} + +/* write() implementation */ +int +fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { + int bytes_copied; + + debug2("write - io:%p", pio); + + if (pio->write_details.pending) { + if (w32_io_is_blocking(pio)) + { + debug2("write - io pending, blocking call made, io:%p", pio); + while (pio->write_details.pending) { + if (wait_for_any_event(NULL, 0, INFINITE) == -1) + return -1; + } + } + else { + errno = EAGAIN; + debug2("write - IO is already pending, io:%p", pio); + return -1; + } + } + + if (pio->write_details.error) { + errno = errno_from_Win32Error(pio->write_details.error); + debug("write - ERROR:%d on prior unblocking write, io:%p", errno, pio); + pio->write_details.error = 0; + if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { + debug("write - ERROR:read end of the pipe closed, io:%p", pio); + errno = EPIPE; + } + return -1; + } + + if (pio->write_details.buf == NULL) { + pio->write_details.buf = malloc(WRITE_BUFFER_SIZE); + if (pio->write_details.buf == NULL) { + errno = ENOMEM; + debug("write - ERROR:%d, io:%p", errno, pio); + return -1; + } + pio->write_details.buf_size = WRITE_BUFFER_SIZE; + } + + bytes_copied = min(max, pio->write_details.buf_size); + memcpy(pio->write_details.buf, buf, bytes_copied); + + if (FILETYPE(pio) == FILE_TYPE_CHAR) { + if (termio_initiate_write(pio, bytes_copied) == 0) { + pio->write_details.pending = TRUE; + pio->write_details.remaining = bytes_copied; + } + else + return -1; + } + else { + if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied, + &pio->write_overlapped, &WriteCompletionRoutine)) { + pio->write_details.pending = TRUE; + pio->write_details.remaining = bytes_copied; + } + else { + errno = errno_from_Win32LastError(); + /* read end of the pipe closed ? */ + if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { + debug("write - ERROR:read end of the pipe closed, io:%p", pio); + errno = EPIPE; + } + debug("write ERROR from cb(2):%d, io:%p", errno, pio); + return -1; + } + } + + if (w32_io_is_blocking(pio)) { + while (pio->write_details.pending) { + if (wait_for_any_event(NULL, 0, INFINITE) == -1) { + /* if interrupted but write has completed, we are good*/ + if ((errno != EINTR) || (pio->write_details.pending)) + return -1; + errno = 0; + } + } + } + /* execute APC to give a chance for write to complete */ + SleepEx(0, TRUE); + + /* if write has completed, pick up any error reported*/ + if (!pio->write_details.pending && pio->write_details.error) { + errno = errno_from_Win32Error(pio->write_details.error); + debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio); + pio->write_details.error = 0; + return -1; + } + debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio); + return bytes_copied; + +} + +/* fstat() implemetation */ +int +fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { + + int fd = _open_osfhandle((intptr_t)pio->handle, 0); + debug2("fstat - pio:%p", pio); + if (fd == -1) { + errno = EOTHER; + return -1; + } + + return _fstat64(fd, buf); +} + +int +fileio_stat(const char *path, struct _stat64 *buf) { + wchar_t wpath[MAX_PATH]; + wchar_t* wtmp = NULL; + + if ((wtmp = utf8_to_utf16(path)) == NULL) + fatal("failed to covert input arguments"); + wcscpy(&wpath[0], wtmp); + free(wtmp); + + return _wstat64(wpath, buf); +} + +long +fileio_lseek(struct w32_io* pio, long offset, int origin) { + debug2("lseek - pio:%p", pio); + if (origin != SEEK_SET) { + debug("lseek - ERROR, origin is not supported %d", origin); + errno = ENOTSUP; + return -1; + } + + pio->read_overlapped.Offset = offset; + pio->write_overlapped.Offset = offset; + return 0; +} + +/* fdopen implementation */ +FILE* +fileio_fdopen(struct w32_io* pio, const char *mode) { + + int fd_flags = 0; + debug2("fdopen - io:%p", pio); + + /* logic below doesn't work with overlapped file HANDLES */ + errno = ENOTSUP; + return NULL; + + if (mode[1] == '\0') { + switch (*mode) { + case 'r': + fd_flags = _O_RDONLY; + break; + case 'w': + break; + case 'a': + fd_flags = _O_APPEND; + break; + default: + errno = ENOTSUP; + debug("fdopen - ERROR unsupported mode %s", mode); + return NULL; + } + } + else { + errno = ENOTSUP; + debug("fdopen - ERROR unsupported mode %s", mode); + return NULL; + } + + int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags); + + if (fd == -1) { + errno = EOTHER; + debug("fdopen - ERROR:%d _open_osfhandle()", errno); + return NULL; + } + + return _fdopen(fd, mode); +} + +void +fileio_on_select(struct w32_io* pio, BOOL rd) { + + if (!rd) + return; + + if (!pio->read_details.pending && !fileio_is_io_available(pio, rd)) + /* initiate read, record any error so read() will pick up */ + if (FILETYPE(pio) == FILE_TYPE_CHAR) { + if (termio_initiate_read(pio) != 0) { + pio->read_details.error = errno; + errno = 0; + return; + } + } + else { + if (fileio_ReadFileEx(pio, INT_MAX) != 0) { + pio->read_details.error = errno; + errno = 0; + return; + } + } +} + + +int +fileio_close(struct w32_io* pio) { + + debug2("fileclose - pio:%p", pio); + + CancelIo(WINHANDLE(pio)); + //let queued APCs (if any) drain + SleepEx(0, TRUE); + if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed + CloseHandle(WINHANDLE(pio)); + + if (pio->read_details.buf) + free(pio->read_details.buf); + + if (pio->write_details.buf) + free(pio->write_details.buf); + + free(pio); + } + return 0; +} + +BOOL +fileio_is_io_available(struct w32_io* pio, BOOL rd) { + if (rd) { + if (pio->read_details.remaining || pio->read_details.error) + return TRUE; + else + return FALSE; + } + else { //write + return (pio->write_details.pending == FALSE) ? TRUE : FALSE; + } +} \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/arpa/inet.h b/contrib/win32/win32compat/inc/arpa/inet.h new file mode 100644 index 000000000..d522ea827 --- /dev/null +++ b/contrib/win32/win32compat/inc/arpa/inet.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_INET_H +#define COMPAT_INET_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/arpa/nameser.h b/contrib/win32/win32compat/inc/arpa/nameser.h new file mode 100644 index 000000000..a9ecc0c34 --- /dev/null +++ b/contrib/win32/win32compat/inc/arpa/nameser.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_NAMESER_H +#define COMPAT_NAMESER_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/crypto-wrap.h b/contrib/win32/win32compat/inc/crypto-wrap.h new file mode 100644 index 000000000..6ed12df54 --- /dev/null +++ b/contrib/win32/win32compat/inc/crypto-wrap.h @@ -0,0 +1,76 @@ + +#ifndef _OPENSSL_WRAP_H +#define _OPENSSL_WRAP_H + +struct sshdh; +struct sshbn; +struct sshbuf; +struct ssh; +struct sshedh; +struct sshepoint; +struct sshecurve; + + +struct sshdh *sshdh_new(void); +void sshdh_free(struct sshdh *dh); +struct sshbn *sshdh_pubkey(struct sshdh *dh); +struct sshbn *sshdh_p(struct sshdh *dh); +struct sshbn *sshdh_g(struct sshdh *dh); +void sshdh_dump(struct sshdh *dh); +size_t sshdh_shared_key_size(struct sshdh *dh); +int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey, +struct sshbn **shared_secretp); +int sshdh_generate(struct sshdh *dh, size_t len); +int sshdh_new_group_hex(const char *gen, const char *modulus, +struct sshdh **dhp); +struct sshdh *sshdh_new_group(struct sshbn *gen, struct sshbn *modulus); + +struct sshedh *sshedh_new(void); +void sshedh_free(struct sshdh *dh); +struct sshepoint *sshedh_pubkey(struct sshedh *dh); +void sshedh_dump(struct sshedh *dh); +size_t sshedh_shared_key_size(struct sshedh *dh); +int sshedh_compute_key(struct sshedh *dh, struct sshepoint *pubkey, +struct sshbn **shared_secretp); +int sshedh_generate(struct sshedh *dh, size_t len); +struct sshedh *sshedh_new_curve(int nid); + +struct sshepoint * sshepoint_new(void); +int sshepoint_from(struct sshbn * x, struct sshbn * y, struct sshecurve * sshecurve, struct sshepoint **retp); +int sshepoint_to(struct sshepoint * pt, struct sshbn **retx, struct sshbn **rety, struct sshecurve ** retcurve); +void sshepoint_free(struct sshepoint * pt); + +struct sshecurve * sshecurve_new(void); +void sshecurve_free(struct sshecurve * curve); +struct sshecurve * sshecurve_new_curve(int nid); + + + +struct sshbn *sshbn_new(void); +void sshbn_free(struct sshbn *bn); +int sshbn_from(const void *d, size_t l, struct sshbn **retp); +int sshbn_from_hex(const char *hex, struct sshbn **retp); +size_t sshbn_bits(const struct sshbn *bn); +const struct sshbn *sshbn_value_0(void); +const struct sshbn *sshbn_value_1(void); +int sshbn_cmp(const struct sshbn *a, const struct sshbn *b); +int sshbn_sub(struct sshbn *r, const struct sshbn *a, const struct sshbn *b); +int sshbn_is_bit_set(const struct sshbn *bn, size_t i); +int sshbn_to(const struct sshbn *a, unsigned char *to); +size_t sshbn_bytes(const struct sshbn *bn); + +/* XXX move to sshbuf.h; rename s/_wrap$// */ +int sshbuf_get_bignum2_wrap(struct sshbuf *buf, struct sshbn *bn); +int sshbuf_get_bignum1_wrap(struct sshbuf *buf, struct sshbn *bn); +int sshbuf_put_bignum2_wrap(struct sshbuf *buf, const struct sshbn *bn); +int sshbuf_put_bignum1_wrap(struct sshbuf *buf, const struct sshbn *bn); +int sshpkt_get_bignum2_wrap(struct ssh *ssh, struct sshbn *bn); +int sshpkt_put_bignum2_wrap(struct ssh *ssh, const struct sshbn *bn); + +/* bridge to unwrapped OpenSSL APIs; XXX remove later */ +struct sshbn *sshbn_from_bignum(BIGNUM *bn); +BIGNUM *sshbn_bignum(struct sshbn *bn); +DH *sshdh_dh(struct sshdh *dh); + + +#endif /* _OPENSSL_WRAP_H */ \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/defs.h b/contrib/win32/win32compat/inc/defs.h new file mode 100644 index 000000000..0bd0a966b --- /dev/null +++ b/contrib/win32/win32compat/inc/defs.h @@ -0,0 +1,97 @@ +/* +* Author: Manoj Ampalam +* +* Redefined and missing POSIX macros +*/ +#pragma once + +#include + +/* total fds that can be allotted */ +#define MAX_FDS 256 /* a 2^n number */ + +#undef FD_ZERO +#define FD_ZERO(set) (memset( (set), 0, sizeof(w32_fd_set))) +#undef FD_SET +#define FD_SET(fd,set) ( (set)->bitmap[(fd) >> 3] |= (0x80 >> ((fd) % 8))) +#undef FD_ISSET +#define FD_ISSET(fd, set) (( (set)->bitmap[(fd) >> 3] & (0x80 >> ((fd) % 8)))?1:0) +#undef FD_CLR +#define FD_CLR(fd, set) ((set)->bitmap[(fd) >> 3] &= (~(0x80 >> ((fd) % 8)))) + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +/*fcntl commands*/ +#define F_GETFL 0x1 +#define F_SETFL 0x2 +#define F_GETFD 0x4 +#define F_SETFD 0x8 + +/*fd flags*/ +#define FD_CLOEXEC 0x1 + +/* signal related defs*/ +/* supported signal types */ +#define W32_SIGINT 0 +#define W32_SIGSEGV 1 + +#define W32_SIGPIPE 2 +#define W32_SIGCHLD 3 +#define W32_SIGALRM 4 +#define W32_SIGTSTP 5 + +#define W32_SIGHUP 6 +#define W32_SIGQUIT 7 +#define W32_SIGTERM 8 +#define W32_SIGTTIN 9 +#define W32_SIGTTOU 10 +#define W32_SIGWINCH 11 + +#define W32_SIGMAX 12 +/* these signals are not supposed to be raised on Windows*/ +#define W32_SIGSTOP 13 +#define W32_SIGABRT 14 +#define W32_SIGFPE 15 +#define W32_SIGILL 16 +#define W32_SIGKILL 17 +#define W32_SIGUSR1 18 +#define W32_SIGUSR2 19 + +/* singprocmask "how" codes*/ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +typedef void(*sighandler_t)(int); +typedef int sigset_t; +#define sigemptyset(set) (memset( (set), 0, sizeof(sigset_t))) +#define sigaddset(set, sig) ( (*(set)) |= (0x80000000 >> (sig))) +#define sigismember(set, sig) ( (*(set) & (0x80000000 >> (sig)))?1:0 ) +#define sigdelset(set, sig) ( (*(set)) &= (~( 0x80000000 >> (sig)) ) ) + +/* signal action codes*/ +#define W32_SIG_ERR ((sighandler_t)-1) +#define W32_SIG_DFL ((sighandler_t)0) +#define W32_SIG_IGN ((sighandler_t)1) + +typedef unsigned short _mode_t; +typedef _mode_t mode_t; +typedef int ssize_t; +/* TODO - investigate if it makes sense to make pid_t a DWORD_PTR. + * Double check usage of pid_t as int */ +typedef int pid_t; + +/* wait pid options */ +#define WNOHANG 1 + +/*ioctl macros and structs*/ +#define TIOCGWINSZ 1 +struct winsize { + unsigned short ws_row; /* rows, in characters */ + unsigned short ws_col; /* columns, in character */ + unsigned short ws_xpixel; /* horizontal size, pixels */ + unsigned short ws_ypixel; /* vertical size, pixels */ +}; + diff --git a/contrib/win32/win32compat/inc/dirent.h b/contrib/win32/win32compat/inc/dirent.h new file mode 100644 index 000000000..a74081518 --- /dev/null +++ b/contrib/win32/win32compat/inc/dirent.h @@ -0,0 +1,25 @@ +// direntry functions in Windows platform like Ubix/Linux +// opendir(), readdir(), closedir(). +// NT_DIR * nt_opendir(char *name) ; +// struct nt_dirent *nt_readdir(NT_DIR *dirp); +// int nt_closedir(NT_DIR *dirp) ; + +#ifndef __DIRENT_H__ +#define __DIRENT_H__ + +#include +#include +#include + +struct dirent { + int d_ino; /* Inode number */ + char d_name[256]; /* Null-terminated filename */ +}; + +typedef struct DIR_ DIR; + +DIR * opendir(const char *name); +int closedir(DIR *dirp); +struct dirent *readdir(void *avp); + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/dlfcn.h b/contrib/win32/win32compat/inc/dlfcn.h new file mode 100644 index 000000000..653604146 --- /dev/null +++ b/contrib/win32/win32compat/inc/dlfcn.h @@ -0,0 +1,11 @@ +#pragma once +#include +#define RTLD_NOW 0 + +#define dlerror() GetLastError() + +HMODULE dlopen(const char *filename, int flags); + +int dlclose(HMODULE handle); + +FARPROC dlsym(HMODULE handle, const char *symbol); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/fcntl.h b/contrib/win32/win32compat/inc/fcntl.h new file mode 100644 index 000000000..1891a13ae --- /dev/null +++ b/contrib/win32/win32compat/inc/fcntl.h @@ -0,0 +1,23 @@ + + +#pragma once + +#define O_RDONLY 0x0000 // open for reading only +#define O_WRONLY 0x0001 // open for writing only +#define O_RDWR 0x0002 // open for reading and writing +#define O_ACCMODE 0x0003 +#define O_APPEND 0x0008 // writes done at eof + +#define O_CREAT 0x0100 // create and open file +#define O_TRUNC 0x0200 // open and truncate +#define O_EXCL 0x0400 // open only if file doesn't already exist + +#define O_TEXT 0x4000 /* file mode is text (translated) */ +#define O_BINARY 0x8000 /* file mode is binary (untranslated) */ +#define O_WTEXT 0x10000 /* file mode is UTF16 (translated) */ +#define O_U16TEXT 0x20000 /* file mode is UTF16 no BOM (translated) */ +#define O_U8TEXT 0x40000 /* file mode is UTF8 no BOM (translated) */ + +#define O_NOCTTY 0x80000 /* TODO - implement this if it makes sense on Windows*/ + +#define F_OK 0 \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/grp.h b/contrib/win32/win32compat/inc/grp.h new file mode 100644 index 000000000..3e4db7504 --- /dev/null +++ b/contrib/win32/win32compat/inc/grp.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_GRP_H +#define COMPAT_GRP_H 1 + +char *group_from_gid(gid_t gid, int nogroup); + +#endif diff --git a/contrib/win32/win32compat/inc/libgen.h b/contrib/win32/win32compat/inc/libgen.h new file mode 100644 index 000000000..b83e65db3 --- /dev/null +++ b/contrib/win32/win32compat/inc/libgen.h @@ -0,0 +1,3 @@ + + +char *basename(char *path); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/netdb.h b/contrib/win32/win32compat/inc/netdb.h new file mode 100644 index 000000000..65ea0c408 --- /dev/null +++ b/contrib/win32/win32compat/inc/netdb.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_NETDB_H +#define COMPAT_NETDB_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/netinet/in.h b/contrib/win32/win32compat/inc/netinet/in.h new file mode 100644 index 000000000..929218138 --- /dev/null +++ b/contrib/win32/win32compat/inc/netinet/in.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_IN_H +#define COMPAT_IN_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/netinet/in_systm.h b/contrib/win32/win32compat/inc/netinet/in_systm.h new file mode 100644 index 000000000..e8cca1056 --- /dev/null +++ b/contrib/win32/win32compat/inc/netinet/in_systm.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_IN_SYSTM_H +#define COMPAT_IN_SYSTM_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/netinet/ip.h b/contrib/win32/win32compat/inc/netinet/ip.h new file mode 100644 index 000000000..7b39a3bf2 --- /dev/null +++ b/contrib/win32/win32compat/inc/netinet/ip.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_IP_H +#define COMPAT_IP_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/netinet/tcp.h b/contrib/win32/win32compat/inc/netinet/tcp.h new file mode 100644 index 000000000..ac933f100 --- /dev/null +++ b/contrib/win32/win32compat/inc/netinet/tcp.h @@ -0,0 +1,7 @@ +#ifndef COMPAT_TCP_H +#define COMPAT_TCP_H 1 + + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/poll.h b/contrib/win32/win32compat/inc/poll.h new file mode 100644 index 000000000..d7d35b9cd --- /dev/null +++ b/contrib/win32/win32compat/inc/poll.h @@ -0,0 +1,7 @@ +#pragma once + +#include "w32posix.h" + +/* created to #def out decarations in open-bsd.h (that are defined in winsock2.h) */ + +int poll(struct pollfd *, nfds_t, int); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/process.h b/contrib/win32/win32compat/inc/process.h new file mode 100644 index 000000000..691a96b98 --- /dev/null +++ b/contrib/win32/win32compat/inc/process.h @@ -0,0 +1,6 @@ +#ifndef Process_H +#define Process_H + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/pwd.h b/contrib/win32/win32compat/inc/pwd.h new file mode 100644 index 000000000..b44ed738b --- /dev/null +++ b/contrib/win32/win32compat/inc/pwd.h @@ -0,0 +1,45 @@ +/* +* Author: Manoj Ampalam +* +* Compatibility header to give us pwd-like functionality on Win32 +* A lot of passwd fields are not applicable in Windows, neither are some API calls based on this structure +* Ideally, usage of this structure needs to be replaced in core SSH code to an ssh_user interface, +* that each platform can extend and implement. +*/ + +#ifndef COMPAT_PWD_H +#define COMPAT_PWD_H 1 + +#include "sys\param.h" + +struct passwd { + char *pw_name; /* user's login name */ + char *pw_passwd; /* password? */ + char *pw_gecos; /* ??? */ + uid_t pw_uid; /* numerical user ID */ + gid_t pw_gid; /* numerical group ID */ + char *pw_dir; /* initial working directory */ + char *pw_shell; /* path to shell */ +}; + +/*start - declarations not applicable in Windows */ +uid_t getuid(void); +gid_t getgid(void); +uid_t geteuid(void); +gid_t getegid(void); +int setuid(uid_t uid); +int setgid(gid_t gid); +int seteuid(uid_t uid); +int setegid(gid_t gid); +char *user_from_uid(uid_t uid, int nouser); + +/*end - declarations not applicable in Windows */ + +struct passwd *w32_getpwuid(uid_t uid); +struct passwd *w32_getpwnam(const char *username); +struct passwd *getpwent(void); + +#define getpwuid w32_getpwuid +#define getpwnam w32_getpwnam + +#endif diff --git a/contrib/win32/win32compat/inc/resolv.h b/contrib/win32/win32compat/inc/resolv.h new file mode 100644 index 000000000..0b449b6b5 --- /dev/null +++ b/contrib/win32/win32compat/inc/resolv.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_RESOLV_H +#define COMPAT_RESOLV_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/signal.h b/contrib/win32/win32compat/inc/signal.h new file mode 100644 index 000000000..c514a722d --- /dev/null +++ b/contrib/win32/win32compat/inc/signal.h @@ -0,0 +1,43 @@ +/* +* Author: Manoj Ampalam +* +* POSIX header and needed function definitions +*/ +#ifndef COMPAT_SIGNAL_H +#define COMPAT_SIGNAL_H 1 + +#include "w32posix.h" + +#define signal(a,b) w32_signal((a), (b)) +#define mysignal(a,b) w32_signal((a), (b)) +#define raise(a) w32_raise(a) +#define kill(a,b) w32_kill((a), (b)) +#define ftruncate(a, b) w32_ftruncate((a), (b)) +#define sigprocmask(a,b,c) w32_sigprocmask((a), (b), (c)) + +#define SIGINT W32_SIGINT +#define SIGSEGV W32_SIGSEGV +#define SIGPIPE W32_SIGPIPE +#define SIGCHLD W32_SIGCHLD +#define SIGALRM W32_SIGALRM +#define SIGTSTP W32_SIGTSTP +#define SIGHUP W32_SIGHUP +#define SIGQUIT W32_SIGQUIT +#define SIGTERM W32_SIGTERM +#define SIGTTIN W32_SIGTTIN +#define SIGTTOU W32_SIGTTOU +#define SIGWINCH W32_SIGWINCH +#define SIGSTOP W32_SIGSTOP +#define SIGSTOP W32_SIGSTOP +#define SIGABRT W32_SIGABRT +#define SIGFPE W32_SIGFPE +#define SIGILL W32_SIGILL +#define SIGKILL W32_SIGKILL +#define SIGUSR1 W32_SIGUSR1 +#define SIGUSR2 W32_SIGUSR2 + +#define SIG_DFL W32_SIG_DFL +#define SIG_IGN W32_SIG_IGN +#define SIG_ERR W32_SIG_ERR + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/sys/ioctl.h b/contrib/win32/win32compat/inc/sys/ioctl.h new file mode 100644 index 000000000..1043e6118 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/ioctl.h @@ -0,0 +1,8 @@ +#ifndef COMPAT_IOCTL_H +#define COMPAT_IOCTL_H 1 + +#include "..\w32posix.h" + +#define ioctl w32_ioctl + +#endif diff --git a/contrib/win32/win32compat/inc/sys/param.h b/contrib/win32/win32compat/inc/sys/param.h new file mode 100644 index 000000000..071f11a9a --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/param.h @@ -0,0 +1,10 @@ +#ifndef COMPAT_PARAM_H +#define COMPAT_PARAM_H 1 + +typedef unsigned int uid_t; +typedef unsigned int gid_t; +typedef long long off_t; +typedef unsigned int dev_t; + + +#endif diff --git a/contrib/win32/win32compat/inc/sys/resource.h b/contrib/win32/win32compat/inc/sys/resource.h new file mode 100644 index 000000000..68799dea4 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/resource.h @@ -0,0 +1,6 @@ +#ifndef COMPAT_RESOURCE_H +#define COMPAT_RESOURCE_H 1 + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/sys/select.h b/contrib/win32/win32compat/inc/sys/select.h new file mode 100644 index 000000000..03b4d67c6 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/select.h @@ -0,0 +1,13 @@ +/* +* Author: Manoj Ampalam +* +* POSIX header and needed function definitions +*/ +#pragma once + +#include "..\w32posix.h" + +#undef FD_SETSIZE +#define FD_SETSIZE MAX_FDS + + diff --git a/contrib/win32/win32compat/inc/sys/socket.h b/contrib/win32/win32compat/inc/sys/socket.h new file mode 100644 index 000000000..a7924383f --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/socket.h @@ -0,0 +1,24 @@ +/* +* Author: Manoj Ampalam +* +* POSIX header and needed function definitions +*/ +#pragma once + +#include "..\w32posix.h" + +#define socket(a,b,c) w32_socket((a), (b), (c)) +#define accept(a,b,c) w32_accept((a), (b), (c)) +#define setsockopt(a,b,c,d,e) w32_setsockopt((a), (b), (c), (d), (e)) +#define getsockopt(a,b,c,d,e) w32_getsockopt((a), (b), (c), (d), (e)) +#define getsockname(a,b,c) w32_getsockname((a), (b), (c)) +#define getpeername(a,b,c) w32_getpeername((a), (b), (c)) +#define listen(a,b) w32_listen((a), (b)) +#define bind(a,b,c) w32_bind((a), (b), (c)) +#define connect(a,b,c) w32_connect((a), (b), (c)) +#define recv(a,b,c,d) w32_recv((a), (b), (c), (d)) +#define send(a,b,c,d) w32_send((a), (b), (c), (d)) +#define shutdown(a,b) w32_shutdown((a), (b)) +#define socketpair(a,b,c,d) w32_socketpair((a), (b), (c), (d)) +#define freeaddrinfo w32_freeaddrinfo +#define getaddrinfo w32_getaddrinfo diff --git a/contrib/win32/win32compat/inc/sys/stat.h b/contrib/win32/win32compat/inc/sys/stat.h new file mode 100644 index 000000000..0b0e0a30e --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/stat.h @@ -0,0 +1,64 @@ +/* +* Author: Manoj Ampalam +* +* private stat.h (all code relying on POSIX wrapper should include this version +* instead of the one in Windows SDK. +*/ +#pragma once +#include "..\fcntl.h" +#include "param.h" + +/* flags COPIED FROM STAT.H + */ +#define _S_IFMT 0xF000 // File type mask +#define _S_IFDIR 0x4000 // Directory +#define _S_IFCHR 0x2000 // Character special +#define _S_IFIFO 0x1000 // Pipe +#define _S_IFREG 0x8000 // Regular +#define _S_IREAD 0x0100 // Read permission, owner +#define _S_IWRITE 0x0080 // Write permission, owner +#define _S_IEXEC 0x0040 // Execute/search permission, owner +#define _S_IFLNK 0xA000 // symbolic link +#define _S_IFSOCK 0xC000 // socket + +#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR +#define S_IFCHR _S_IFCHR +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IEXEC _S_IEXEC +#define S_IFLNK _S_IFLNK +#define S_IFSOCK _S_IFSOCK + + /* TODO - is this the right place for these defs ?*/ +# define S_ISUID 0x800 +# define S_ISGID 0x400 + +#define stat w32_stat +#define lstat w32_stat +#define mkdir w32_mkdir +#define chmod w32_chmod + +struct w32_stat { + dev_t st_dev; /* ID of device containing file */ + unsigned short st_ino; /* inode number */ + unsigned short st_mode; /* protection */ + short st_nlink; /* number of hard links */ + short st_uid; /* user ID of owner */ + short st_gid; /* group ID of owner */ + dev_t st_rdev; /* device ID (if special file) */ + __int64 st_size; /* total size, in bytes */ + __int64 st_atime; /* time of last access */ + __int64 st_mtime; /* time of last modification */ + __int64 st_ctime; /* time of last status change */ +}; + +typedef unsigned short _mode_t; +typedef _mode_t mode_t; + +void strmode(mode_t mode, char *p); +int w32_chmod(const char *, mode_t); +int w32_mkdir(const char *pathname, unsigned short mode); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/sys/statvfs.h b/contrib/win32/win32compat/inc/sys/statvfs.h new file mode 100644 index 000000000..8f14361a9 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/statvfs.h @@ -0,0 +1,26 @@ +#pragma once + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +typedef unsigned long fsblkcnt_t; +typedef unsigned long fsfilcnt_t; + +struct statvfs { + unsigned long f_bsize; /* File system block size. */ + unsigned long f_frsize; /* Fundamental file system block size. */ + fsblkcnt_t f_blocks; /* Total number of blocks on file system in */ + /* units of f_frsize. */ + fsblkcnt_t f_bfree; /* Total number of free blocks. */ + fsblkcnt_t f_bavail; /* Number of free blocks available to */ + /* non-privileged process. */ + fsfilcnt_t f_files; /* Total number of file serial numbers. */ + fsfilcnt_t f_ffree; /* Total number of free file serial numbers. */ + fsfilcnt_t f_favail; /* Number of file serial numbers available to */ + /* non-privileged process. */ + unsigned long f_fsid; /* File system ID. */ + unsigned long f_flag; /* BBit mask of f_flag values. */ + unsigned long f_namemax;/* Maximum filename length. */ +}; + +int statvfs(const char *, struct statvfs *); +int fstatvfs(int, struct statvfs *); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/sys/time.h b/contrib/win32/win32compat/inc/sys/time.h new file mode 100644 index 000000000..27b08c34b --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/time.h @@ -0,0 +1,9 @@ +#include + +#define utimbuf _utimbuf +#define utimes w32_utimes + +int usleep(unsigned int); +int gettimeofday(struct timeval *tv, void *tz); +int nanosleep(const struct timespec *req, struct timespec *rem); +int w32_utimes(const char *filename, struct timeval *tvp); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/sys/uio.h b/contrib/win32/win32compat/inc/sys/uio.h new file mode 100644 index 000000000..dd51934c6 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/uio.h @@ -0,0 +1,7 @@ +#ifndef COMPAT_UIO_H +#define COMPAT_UIO_H 1 + + +/* Compatibility header to avoid #ifdefs on Win32 */ + +#endif diff --git a/contrib/win32/win32compat/inc/sys/un.h b/contrib/win32/win32compat/inc/sys/un.h new file mode 100644 index 000000000..fff9d7891 --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/un.h @@ -0,0 +1,7 @@ +#ifndef COMPAT_UN_H +#define COMPAT_UN_H 1 + + +/* Compatibility header to avoid lots of #ifdef _WIN32's in includes.h */ + +#endif diff --git a/contrib/win32/win32compat/inc/sys/wait.h b/contrib/win32/win32compat/inc/sys/wait.h new file mode 100644 index 000000000..312486b9c --- /dev/null +++ b/contrib/win32/win32compat/inc/sys/wait.h @@ -0,0 +1,19 @@ +#pragma once +#include "..\w32posix.h" + +//#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */ +//#define WIFEXITED(w) (!((_W_INT(w)) & 0377)) +//#define WIFSTOPPED(w) ((_W_INT(w)) & 0100) +//#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w)) +//#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1) +//#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1) + +#define WIFEXITED(w) TRUE +#define WIFSTOPPED(w) TRUE +#define WIFSIGNALED(w) FALSE +#define WEXITSTATUS(w) w +#define WTERMSIG(w) -1 +#define WNOHANG 1 +#define WUNTRACED 2 + +int waitpid(int pid, int *status, int options); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/syslog.h b/contrib/win32/win32compat/inc/syslog.h new file mode 100644 index 000000000..28e67fbed --- /dev/null +++ b/contrib/win32/win32compat/inc/syslog.h @@ -0,0 +1,28 @@ +#pragma once + + +/* Compatibility header to give us some syslog-like functionality on Win32 */ + +#define LOG_CRIT (2) /* critical */ +#define LOG_ERR (3) /* errors */ +#define LOG_WARNING (4) /* warnings */ +#define LOG_INFO (6) /* informational */ +#define LOG_DEBUG (7) /* debug messages */ +#define LOG_USER (1 << 3) /* user level messages */ +#define LOG_DAEMON (3 << 3) /* daemons/servers */ +#define LOG_AUTH (4 << 3) /* security messages */ +#define LOG_LOCAL0 (16 << 3) /* reserved for local use */ +#define LOG_LOCAL1 (17 << 3) /* reserved for local use */ +#define LOG_LOCAL2 (18 << 3) /* reserved for local use */ +#define LOG_LOCAL3 (19 << 3) /* reserved for local use */ +#define LOG_LOCAL4 (20 << 3) /* reserved for local use */ +#define LOG_LOCAL5 (21 << 3) /* reserved for local use */ +#define LOG_LOCAL6 (22 << 3) /* reserved for local use */ +#define LOG_LOCAL7 (23 << 3) /* reserved for local use */ + +#define LOG_PID 0x01 /* log the pid */ + +void openlog (char *, unsigned int, int); +void closelog (void); +void syslog (int, const char *, const char *); + diff --git a/contrib/win32/win32compat/inc/termios.h b/contrib/win32/win32compat/inc/termios.h new file mode 100644 index 000000000..9d961dbd8 --- /dev/null +++ b/contrib/win32/win32compat/inc/termios.h @@ -0,0 +1,110 @@ +#ifndef COMPAT_TERMIOS_H +#define COMPAT_TERMIOS_H 1 + +#define B0 0x00000000 +#define B50 0x00000001 +#define B75 0x00000002 +#define B110 0x00000003 +#define B134 0x00000004 +#define B150 0x00000005 +#define B200 0x00000006 +#define B300 0x00000007 +#define B600 0x00000008 +#define B1200 0x00000009 +#define B1800 0x0000000a +#define B2400 0x0000000b +#define B4800 0x0000000c +#define B9600 0x0000000d +#define B19200 0x0000000e +#define B38400 0x0000000f + +#define BRKINT 0x00000100 +#define ICRNL 0x00000200 +#define IGNBRK 0x00000400 +#define IGNCR 0x00000800 +#define IGNPAR 0x00001000 +#define INLCR 0x00002000 +#define INPCK 0x00004000 +#define ISTRIP 0x00008000 +#define IXOFF 0x00010000 +#define IXON 0x00020000 +#define PARMRK 0x00040000 +#ifndef _POSIX_SOURCE +#define IXANY 0x00000800 /* any char will restart after stop */ +#define IMAXBEL 0x00002000 /* ring bell on input queue full */ +#endif /*_POSIX_SOURCE */ + +#define OPOST 0x00000100 + +#define CLOCAL 0x00000100 +#define CREAD 0x00000200 +#define CS5 0x00000000 +#define CS6 0x00000400 +#define CS7 0x00000800 +#define CS8 0x00000c00 +#define CSIZE 0x00000c00 +#define CSTOPB 0x00001000 +#define HUPCL 0x00002000 +#define PARENB 0x00004000 +#define PARODD 0x00008000 + +#define ECHO 0x00000100 +#define ECHOE 0x00000200 +#define ECHOK 0x00000400 +#define ECHONL 0x00000800 +#define ICANON 0x00001000 +#define IEXTEN 0x00002000 +#define ISIG 0x00004000 +#define NOFLSH 0x00008000 +#define TOSTOP 0x00010000 + +#define TCIFLUSH 1 +#define TCOFLUSH 2 +#define TCIOFLUSH 3 +#define TCOOFF 1 +#define TCOON 2 +#define TCIOFF 3 +#define TCION 4 + +#define TCSADRAIN 1 +#define TCSAFLUSH 2 +#define TCSANOW 3 + +/* Compatibility header to allow some termios functionality to compile without #ifdefs */ + +#define VDISCARD 1 +#define VEOL 2 +#define VEOL2 3 +#define VEOF 4 +#define VERASE 5 +#define VINTR 6 +#define VKILL 7 +#define VLNEXT 8 +#define VMIN 9 +#define VQUIT 10 +#define VREPRINT 11 +#define VSTART 12 +#define VSTOP 13 +#define VSUSP 14 +#define VSWTC 15 +#define VTIME 16 +#define VWERASE 17 +#define NCCS 18 + +typedef unsigned char cc_t; +typedef unsigned int tcflag_t; +typedef unsigned int speed_t; + +struct termios +{ + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + char c_line; + cc_t c_cc[NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + +#endif diff --git a/contrib/win32/win32compat/inc/unistd.h b/contrib/win32/win32compat/inc/unistd.h new file mode 100644 index 000000000..5e4ca6804 --- /dev/null +++ b/contrib/win32/win32compat/inc/unistd.h @@ -0,0 +1,50 @@ +/* +* Author: Manoj Ampalam +* +* POSIX header and needed function definitions +*/ +#ifndef COMPAT_UNISTD_H +#define COMPAT_UNISTD_H 1 + +#include "w32posix.h" + +#define pipe w32_pipe +#define open w32_open +#define read w32_read +#define write w32_write +#define writev w32_writev +/* can't do this #define isatty w32_isatty +* as there is a variable in code named isatty*/ +#define isatty(a) w32_isatty((a)) +#define close w32_close +#define dup w32_dup +#define dup2 w32_dup2 + +#define sleep(sec) Sleep(1000 * sec) +#define alarm w32_alarm +#define lseek w32_lseek + +#define getdtablesize() MAX_FDS +#define gethostname w32_gethostname + +#define fsync(a) w32_fsync((a)) +#define ftruncate(a, b) w32_ftruncate((a), (b)) + +#define symlink w32_symlink +#define chown w32_chown +#define unlink w32_unlink +#define rmdir w32_rmdir +#define chdir w32_chdir +#define getcwd w32_getcwd + +int daemon(int nochdir, int noclose); +char *crypt(const char *key, const char *salt); +int link(const char *oldpath, const char *newpath); +int w32_symlink(const char *target, const char *linkpath); +int w32_chown(const char *pathname, unsigned int owner, unsigned int group); +int w32_unlink(const char *path); +int w32_rmdir(const char *pathname); +int w32_chdir(const char *dirname); +char *w32_getcwd(char *buffer, int maxlen); +int readlink(const char *path, char *link, int linklen); +#endif diff --git a/contrib/win32/win32compat/inc/utf.h b/contrib/win32/win32compat/inc/utf.h new file mode 100644 index 000000000..1e959b566 --- /dev/null +++ b/contrib/win32/win32compat/inc/utf.h @@ -0,0 +1,12 @@ +/* +* Author: Manoj Ampalam +* +* UTF-16 <--> UTF-8 definitions +*/ +#ifndef UTF_H +#define UTF_H 1 + +wchar_t* utf8_to_utf16(const char *); +char* utf16_to_utf8(const wchar_t*); + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/w32posix.h b/contrib/win32/win32compat/inc/w32posix.h new file mode 100644 index 000000000..0236b3c7a --- /dev/null +++ b/contrib/win32/win32compat/inc/w32posix.h @@ -0,0 +1,161 @@ +/* +* Author: Manoj Ampalam +* +* Win32 renamed POSIX APIs +*/ +#pragma once +#include +#include +#include +#include "defs.h" +#include "utf.h" +#include "sys\param.h" + +typedef struct w32_fd_set_ { + unsigned char bitmap[MAX_FDS >> 3]; +}w32_fd_set; + +#define fd_set w32_fd_set + +void w32posix_initialize(); +void w32posix_done(); + +/*network i/o*/ +int w32_socket(int domain, int type, int protocol); +int w32_accept(int fd, struct sockaddr* addr, int* addrlen); +int w32_setsockopt(int fd, int level, int optname, const void* optval, int optlen); +int w32_getsockopt(int fd, int level, int optname, void* optval, int* optlen); +int w32_getsockname(int fd, struct sockaddr* name, int* namelen); +int w32_getpeername(int fd, struct sockaddr* name, int* namelen); +int w32_listen(int fd, int backlog); +int w32_bind(int fd, const struct sockaddr *name, int namelen); +int w32_connect(int fd, const struct sockaddr* name, int namelen); +int w32_recv(int fd, void *buf, size_t len, int flags); +int w32_send(int fd, const void *buf, size_t len, int flags); +int w32_shutdown(int fd, int how); +int w32_socketpair(int domain, int type, int protocol, int sv[2]); + +/*non-network (file) i/o*/ +#undef fdopen +#define fdopen(a,b) w32_fdopen((a), (b)) +#define fstat(a,b) w32_fstat((a), (b)) + +#define rename w32_rename + +struct w32_stat; +int w32_pipe(int *pfds); +int w32_open(const char *pathname, int flags, ...); +int w32_read(int fd, void *dst, size_t max); +int w32_write(int fd, const void *buf, unsigned int max); +int w32_writev(int fd, const struct iovec *iov, int iovcnt); +int w32_fstat(int fd, struct w32_stat *buf); +int w32_stat(const char *path, struct w32_stat *buf); +long w32_lseek( int fd, long offset, int origin); +int w32_isatty(int fd); +FILE* w32_fdopen(int fd, const char *mode); +int w32_rename(const char *old_name, const char *new_name); + +/*common i/o*/ +#define fcntl(a,b,...) w32_fcntl((a), (b), __VA_ARGS__) +#define select(a,b,c,d,e) w32_select((a), (b), (c), (d), (e)) +int w32_close(int fd); +int w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* exceptfds, + const struct timeval *timeout); +int w32_fcntl(int fd, int cmd, ... /* arg */); +int w32_dup(int oldfd); +int w32_dup2(int oldfd, int newfd); + + +/* misc */ +unsigned int w32_alarm(unsigned int seconds); +sighandler_t w32_signal(int signum, sighandler_t handler); +int w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +int w32_raise(int sig); +int w32_kill(int pid, int sig); +int w32_gethostname(char *, size_t); +void w32_freeaddrinfo(struct addrinfo *); +int w32_getaddrinfo(const char *, const char *, + const struct addrinfo *, struct addrinfo **); +FILE* w32_fopen_utf8(const char *, const char *); +int w32_ftruncate(int fd, off_t length); +char* w32_programdir(); +int w32_fsync(int fd); +int w32_ioctl(int d, int request, ...); + +/* Shutdown constants */ +#define SHUT_WR SD_SEND +#define SHUT_RD SD_RECEIVE +#define SHUT_RDWR SD_BOTH + +/* Other constants */ +#define IN_LOOPBACKNET 127 /* 127.* is the loopback network */ +#define MAXHOSTNAMELEN 64 + + +/* Errno helpers */ +#ifndef EXX +#define EXX WSAEMFILE +#endif +#ifndef EXX1 +#define EXX1 WSAENOBUFS +#endif +#ifndef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#endif +#ifndef ENOTUNREACH +#define ENOTUNREACH WSAENOTUNREACH +#endif +#ifndef EPFNOSUPPORT +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#endif + +int spawn_child(char* cmd, int in, int out, int err, DWORD flags); + + +/* + * these routines are temporarily defined here to allow transition + * from older POSIX wrapper to the newer one. After complete transition + * these should be gone or moved to a internal header. + */ +HANDLE w32_fd_to_handle(int fd); +int w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock); +int sw_add_child(HANDLE child, DWORD pid); + +/* temporary definitions to aid in transition */ +#define sfd_to_handle(a) w32_fd_to_handle((a)) + +/* TODO - These defs need to revisited and positioned appropriately */ +#define environ _environ + +typedef unsigned int nfds_t; + +struct w32_pollfd { + + int fd; + SHORT events; + SHORT revents; + +}; + +#define pollfd w32_pollfd + +struct iovec +{ + void *iov_base; + size_t iov_len; +}; + + +#define bzero(p,l) memset((void *)(p),0,(size_t)(l)) + +void +explicit_bzero(void *b, size_t len); + +/* string.h overrides */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp + +/* stdio.h overrides */ +#define fopen w32_fopen_utf8 +#define popen _popen +#define pclose _pclose diff --git a/contrib/win32/win32compat/inc/zlib.h b/contrib/win32/win32compat/inc/zlib.h new file mode 100644 index 000000000..62d77ff7a --- /dev/null +++ b/contrib/win32/win32compat/inc/zlib.h @@ -0,0 +1,76 @@ +/* + * Temporary zlib.h header for Windows + * TODO - decide on a compression solution for Windows + */ +#pragma once +#include + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) + +#define Z_PARTIAL_FLUSH 1 + +#define voidpf void* +typedef voidpf(*alloc_func)(voidpf opaque, unsigned int items, unsigned int size); +typedef void(*free_func)(voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + char *next_in; /* next input byte */ + unsigned int avail_in; /* number of bytes available at next_in */ + unsigned long total_in; /* total number of input bytes read so far */ + + char *next_out; /* next output byte should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total number of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +int +deflateEnd(z_streamp strm); + +int +inflateEnd(z_streamp strm); + +int +deflateInit(z_streamp strm, int level); + +int +inflateInit(z_streamp strm); + +int +deflate(z_streamp strm, int flush); + +int +inflate(z_streamp strm, int flush); + + + + + + + + + + + diff --git a/contrib/win32/win32compat/libwin32compat.q b/contrib/win32/win32compat/libwin32compat.q new file mode 100644 index 000000000..8b277f0dd --- /dev/null +++ b/contrib/win32/win32compat/libwin32compat.q @@ -0,0 +1 @@ +! diff --git a/contrib/win32/win32compat/lsa/Ssh-lsa.c b/contrib/win32/win32compat/lsa/Ssh-lsa.c new file mode 100644 index 000000000..26a69c6f7 --- /dev/null +++ b/contrib/win32/win32compat/lsa/Ssh-lsa.c @@ -0,0 +1,357 @@ +/* + * Author: NoMachine + * Copyright (c) 2009, 2013 NoMachine + * All rights reserved + * + * Author: Manoj Ampalam + * Simplified code to just perform local user logon + * + * 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. + */ + +#define WINVER 0x501 + +#define UMDF_USING_NTSTATUS +#include +#define SECURITY_WIN32 +#include +#include +#include +#include +#include + +#define Unsigned unsigned +#define Char char +#define Int int +#define Long long +#define Not(value) ((value) == 0) +#define PKG_NAME "SSH-LSA" +#define PKG_NAME_SIZE sizeof(PKG_NAME) +#define MAX_ACCOUNT_NAME_SIZE (256 * 2) +#define VERSION "4.0.346" + + +typedef VOID(WINAPI *RtlInitUnicodeStringPtr) +(PUNICODE_STRING, PCWSTR SourceString); +#define FAIL(CONDITION) if(CONDITION) goto fail + +#define NTFAIL(NTFUNC) if((ntStat = (NTFUNC))) goto fail + +RtlInitUnicodeStringPtr RtlInitUnicodeString = NULL; +HMODULE NtDll = NULL; +LSA_SECPKG_FUNCTION_TABLE LsaApi; + +NTSTATUS LsaAllocUnicodeString(PUNICODE_STRING *lsaStr, USHORT maxLen) +{ + NTSTATUS ntStat = STATUS_NO_MEMORY; + FAIL(lsaStr == NULL); + *lsaStr = (PUNICODE_STRING)LsaApi.AllocateLsaHeap(sizeof(UNICODE_STRING)); + FAIL((*lsaStr) == NULL); + (*lsaStr)->Buffer = (WCHAR *)LsaApi.AllocateLsaHeap(sizeof(maxLen)); + (*lsaStr)->Length = 0; + (*lsaStr)->MaximumLength = maxLen; + FAIL((*lsaStr)->Buffer == NULL); + + ntStat = 0; +fail: + + if (ntStat) { + if (lsaStr && (*lsaStr)) { + LsaApi.FreeLsaHeap((*lsaStr)->Buffer); + LsaApi.FreeLsaHeap((*lsaStr)); + } + } + + return ntStat; +} + +void LsaFreeUnicodeString(PUNICODE_STRING lsaStr) +{ + if (lsaStr) { + if (lsaStr->Buffer) + LsaApi.FreeLsaHeap(lsaStr->Buffer); + LsaApi.FreeLsaHeap(lsaStr); + } +} + +NTSTATUS FillUnicodeString(UNICODE_STRING *lsaStr, const Char *str) +{ + NTSTATUS ntStat = STATUS_NO_MEMORY; + size_t cbSize = 0; + FAIL(lsaStr == NULL); + FAIL(lsaStr->Buffer == NULL); + FAIL(str == NULL); + cbSize = strlen(str); + FAIL(cbSize >= lsaStr->MaximumLength); + _swprintf(lsaStr->Buffer, L"%hs", str); + lsaStr->Length = (USHORT)(cbSize * 2); + lsaStr->Buffer[cbSize * 2] = 0x0000; + ntStat = STATUS_SUCCESS; + +fail: + return ntStat; +} + + +NTSTATUS NTAPI LsaApCallPackagePassthrough(PLSA_CLIENT_REQUEST request, + PVOID submitBuf, + PVOID clientBufBase, + ULONG submitBufSize, + PVOID *outBuf, + PULONG outBufSize, + PNTSTATUS status) { + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS NTAPI LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST request, + PVOID submitBuf, + PVOID clientBufBase, + ULONG submitBufSize, + PVOID *outBuf, + PULONG outBufSize, + PNTSTATUS status) { + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS NTAPI LsaApCallPackage(PLSA_CLIENT_REQUEST request, PVOID submitBuf, + PVOID clientBufBase, ULONG submitBufSize, + PVOID *outBuf, PULONG outBufSize, + PNTSTATUS status) { + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS NTAPI LsaApInitializePackage(ULONG pkgId, + PLSA_SECPKG_FUNCTION_TABLE func, + PLSA_STRING database, + PLSA_STRING confident, + PLSA_STRING *pkgName) +{ + memcpy(&LsaApi, func, sizeof(LsaApi)); + + *pkgName = (PLSA_STRING)LsaApi.AllocateLsaHeap(sizeof(LSA_STRING)); + (*pkgName)->Buffer = (PCHAR)LsaApi.AllocateLsaHeap(PKG_NAME_SIZE); + + /* fill buffer with package name */ + memcpy((*pkgName)->Buffer, PKG_NAME, PKG_NAME_SIZE); + (*pkgName)->Length = PKG_NAME_SIZE - 1; + (*pkgName)->MaximumLength = PKG_NAME_SIZE; + + return STATUS_SUCCESS; +} + +int LsaCopySid(PSID *dst, PSID src) +{ + int exitCode = 1; + DWORD size = 0; + + FAIL(IsValidSid(src) == FALSE); + size = GetLengthSid(src); + *dst = LsaApi.AllocateLsaHeap(size); + memcpy(*dst, src, size); + exitCode = 0; +fail: + return exitCode; +} + +int LsaAllocTokenInfo(PLSA_TOKEN_INFORMATION_V1 *info, HANDLE token) +{ + + int exitCode = 1; + DWORD cbSize = 0; + DWORD i = 0; + + PTOKEN_USER pUserToken = NULL; + PTOKEN_GROUPS pGroupsToken = NULL; + PTOKEN_OWNER pOwnerToken = NULL; + PTOKEN_PRIMARY_GROUP pPrimaryGroupToken = NULL; + PLSA_TOKEN_INFORMATION_V1 tokenInfo; + + *info = (PLSA_TOKEN_INFORMATION_V1) + LsaApi.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1)); + + FAIL(*info == NULL); + tokenInfo = *info; + GetTokenInformation(token, TokenUser, NULL, 0, &cbSize); + pUserToken = (PTOKEN_USER)LocalAlloc(LPTR, cbSize); + FAIL(GetTokenInformation(token, TokenUser, + pUserToken, cbSize, &cbSize) == FALSE); + tokenInfo->User.User.Attributes = pUserToken->User.Attributes; + FAIL(LsaCopySid(&tokenInfo->User.User.Sid, pUserToken->User.Sid)); + + GetTokenInformation(token, TokenGroups, NULL, 0, &cbSize); + pGroupsToken = (PTOKEN_GROUPS)LocalAlloc(LPTR, cbSize); + FAIL(GetTokenInformation(token, TokenGroups, + pGroupsToken, cbSize, &cbSize) == FALSE); + cbSize = pGroupsToken->GroupCount * sizeof(SID_AND_ATTRIBUTES) + sizeof(DWORD); + tokenInfo->Groups = (PTOKEN_GROUPS)LsaApi.AllocateLsaHeap(cbSize); + tokenInfo->Groups->GroupCount = pGroupsToken->GroupCount; + + for (i = 0; i < pGroupsToken->GroupCount; i++) + { + FAIL(LsaCopySid(&tokenInfo->Groups->Groups[i].Sid, + pGroupsToken->Groups[i].Sid)); + + tokenInfo->Groups->Groups[i].Attributes = pGroupsToken->Groups[i].Attributes; + } + + GetTokenInformation(token, TokenPrivileges, NULL, 0, &cbSize); + tokenInfo->Privileges = (PTOKEN_PRIVILEGES)LsaApi.AllocateLsaHeap(cbSize); + FAIL(GetTokenInformation(token, TokenPrivileges, + tokenInfo->Privileges, cbSize, &cbSize) == FALSE); + GetTokenInformation(token, TokenOwner, NULL, 0, &cbSize); + pOwnerToken = (PTOKEN_OWNER)LocalAlloc(LPTR, cbSize); + FAIL(GetTokenInformation(token, TokenOwner, + pOwnerToken, cbSize, &cbSize) == FALSE); + FAIL(LsaCopySid(&tokenInfo->Owner.Owner, pOwnerToken->Owner)); + + GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &cbSize); + pPrimaryGroupToken = (PTOKEN_PRIMARY_GROUP)LocalAlloc(LPTR, cbSize); + FAIL(GetTokenInformation(token, TokenPrimaryGroup, + pPrimaryGroupToken, cbSize, &cbSize) == FALSE); + FAIL(LsaCopySid(&tokenInfo->PrimaryGroup.PrimaryGroup, + pPrimaryGroupToken->PrimaryGroup)); + + tokenInfo->DefaultDacl.DefaultDacl = NULL; + tokenInfo->ExpirationTime.HighPart = 0x7fffffff; + tokenInfo->ExpirationTime.LowPart = 0xffffffff; + exitCode = 0; + +fail: + LsaApi.FreeLsaHeap(pUserToken); + LsaApi.FreeLsaHeap(pGroupsToken); + LsaApi.FreeLsaHeap(pOwnerToken); + LsaApi.FreeLsaHeap(pPrimaryGroupToken); + + return exitCode; +} + + +NTSTATUS NTAPI +LsaApLogonUser(PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logonType, + PVOID authData, PVOID clientAuthData, ULONG authDataSize, + PVOID *profile, PULONG profileSize, PLUID logonId, + PNTSTATUS subStat, + PLSA_TOKEN_INFORMATION_TYPE tokenInfoType, + PVOID *tokenInfo, + PLSA_UNICODE_STRING *accountName, + PLSA_UNICODE_STRING *authority) +{ + + NTSTATUS ntStat = STATUS_LOGON_FAILURE; + int exitCode = 1; + wchar_t *inUserName = NULL; + WCHAR samUserBuf[MAX_ACCOUNT_NAME_SIZE + 1]; + SECURITY_STRING samUser; + UNICODE_STRING *flatName = NULL; + UCHAR *userAuth = NULL; + ULONG userAuthSize; + wchar_t homeDir[MAX_PATH]; + TOKEN_SOURCE tokenSource; + + HANDLE token = NULL; + HANDLE clientToken = NULL; + SECPKG_CLIENT_INFO clientInfo; + inUserName = (wchar_t *)authData; + + NTFAIL(LsaApi.GetClientInfo(&clientInfo)); + FAIL(Not(clientInfo.HasTcbPrivilege)); + NTFAIL(LsaAllocUnicodeString(authority, MAX_ACCOUNT_NAME_SIZE)); + NTFAIL(LsaAllocUnicodeString(accountName, MAX_ACCOUNT_NAME_SIZE)); + NTFAIL(LsaAllocUnicodeString(&flatName, MAX_ACCOUNT_NAME_SIZE)); + + lstrcpyW(samUserBuf, inUserName); + samUserBuf[MAX_ACCOUNT_NAME_SIZE] = 0x00; + RtlInitUnicodeString((PUNICODE_STRING)&samUser, samUserBuf); + NTFAIL(LsaApi.GetAuthDataForUser(&samUser, SecNameFlat, NULL, + &userAuth, &userAuthSize, flatName)); + + memcpy(tokenSource.SourceName, "_sshlsa_", 8); + AllocateLocallyUniqueId(&tokenSource.SourceIdentifier); + NTFAIL(LsaApi.ConvertAuthDataToToken(userAuth, userAuthSize, + SecurityDelegation, + &tokenSource, Network, + *authority, &token, logonId, + *accountName, subStat)); + + NTFAIL(LsaApi.AllocateClientBuffer(request, MAX_PATH * sizeof(wchar_t), profile)); + *profileSize = MAX_PATH; + NTFAIL(LsaApi.CopyToClientBuffer(request, MAX_PATH * sizeof(wchar_t), + *profile, homeDir)); + + PLSA_TOKEN_INFORMATION_V1 outTokenInfo; + FAIL(LsaAllocTokenInfo(&outTokenInfo, token)); + *tokenInfoType = LsaTokenInformationV1; + *tokenInfo = outTokenInfo; + + NTFAIL(LsaApi.DuplicateHandle(token, &clientToken)); + ntStat = STATUS_SUCCESS; + exitCode = 0; + +fail: + if (exitCode) + { + ntStat = STATUS_LOGON_FAILURE; + CloseHandle(clientToken); + LsaApi.DeleteLogonSession(logonId); + *profileSize = 0; + } + + CloseHandle(token); + LsaFreeUnicodeString(flatName); + return ntStat; +} + + +VOID NTAPI LsaApLogonTerminated(PLUID logonId) +{ +} + +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpRes) +{ + BOOL exitCode = FALSE; + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + { + NtDll = GetModuleHandle("ntdll.dll"); + + FAIL(NtDll == NULL); + RtlInitUnicodeString = (RtlInitUnicodeStringPtr) + GetProcAddress(NtDll, "RtlInitUnicodeString"); + FAIL(RtlInitUnicodeString == NULL); + break; + } + + case DLL_PROCESS_DETACH: + FreeModule(NtDll); + } + + exitCode = TRUE; + +fail: + + if (exitCode == FALSE) + FreeModule(NtDll); + + return exitCode; +} diff --git a/contrib/win32/win32compat/lsastring.c b/contrib/win32/win32compat/lsastring.c new file mode 100644 index 000000000..7543b5454 --- /dev/null +++ b/contrib/win32/win32compat/lsastring.c @@ -0,0 +1,152 @@ +/* + * Author: NoMachine + * + * Copyright (c) 2009, 2011 NoMachine + * All rights reserved + * + * Support functions and system calls' replacements needed to let the + * software run on Win32 based operating systems. + * + * 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 "LsaString.h" + +/* + * Allocate UNICODE_STRING's buffer and initializes it with + * given string. + * + * lsaStr - UNICODE_STRING to initialize (IN/OUT) + * wstr - string, which will be copied to lsaStr (IN) + * + * RETURNS: 0 if OK. + */ + +int InitUnicodeString(UNICODE_STRING *lsaStr, const wchar_t *wstr) +{ + int exitCode = 1; + + int size = (wstr) ? wcslen(wstr) * 2 : 0; + + lsaStr -> Length = size; + lsaStr -> MaximumLength = size + 2; + lsaStr -> Buffer = (wchar_t *) malloc(size + 2); + + FAIL(lsaStr -> Buffer == NULL); + + memcpy(lsaStr -> Buffer, wstr, size); + + lsaStr -> Buffer[size / 2] = 0; + + exitCode = 0; + +fail: + + if (exitCode) + { + printf("ERROR. Cannot initialize UNICODE_STRING..."); + } + + return exitCode; +} + + +/* + * Allocate LSA_STRING's buffer and initializes it with + * given string. + * + * lsaStr - LSA_STRING to initialize (IN/OUT) + * str - string, which will be copied to lsaStr (IN) + * + * RETURNS: 0 if OK. + */ + +int InitLsaString(LSA_STRING *lsaStr, const char *str) +{ + int exitCode = 1; + + int len = (str) ? strlen(str) : 0; + + lsaStr -> Length = len; + lsaStr -> MaximumLength = len + 1; + lsaStr -> Buffer = (char *) malloc(len + 1); + + FAIL(lsaStr -> Buffer == NULL); + + memcpy(lsaStr -> Buffer, str, len); + + lsaStr -> Buffer[len] = 0; + + exitCode = 0; + +fail: + + if (exitCode) + { + printf("ERROR. Cannot initialize LSA_STRING..."); + } + + return exitCode; +} + + +/* + * Clear LSA_STRING's buffer. + * + * lsaStr - LSA_STRING to clear (IN/OUT) + */ + +void ClearLsaString(LSA_STRING *lsaStr) +{ + if (lsaStr) + { + if (lsaStr -> Buffer) + { + free(lsaStr -> Buffer); + + lsaStr -> Buffer = NULL; + } + lsaStr -> MaximumLength = 0; + lsaStr -> Length = 0; + } +} + +/* + * Clear UNICODE_STRING's buffer. + * + * lsaStr - UNICODE_STRING to clear (IN/OUT) + */ + +void ClearUnicodeString(UNICODE_STRING *lsaStr) +{ + if (lsaStr) + { + if (lsaStr -> Buffer) + { + free(lsaStr -> Buffer); + + lsaStr -> Buffer = NULL; + } + lsaStr -> MaximumLength = 0; + lsaStr -> Length = 0; + } +} diff --git a/contrib/win32/win32compat/lsastring.h b/contrib/win32/win32compat/lsastring.h new file mode 100644 index 000000000..5f7a7fc5a --- /dev/null +++ b/contrib/win32/win32compat/lsastring.h @@ -0,0 +1,50 @@ +/* + * Author: NoMachine + * + * Copyright (c) 2009, 2011 NoMachine + * All rights reserved + * + * Support functions and system calls' replacements needed to let the + * software run on Win32 based operating systems. + * + * 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. + */ + +#ifndef LsaString_H +#define LsaString_H + + +#include +#include +#include + +#include "Debug.h" + +int InitUnicodeString(UNICODE_STRING *lsaStr, const wchar_t *wstr); + +void ClearUnicodeString(UNICODE_STRING *lsaStr); + +int InitLsaString(LSA_STRING *lsaStr, const char *str); + +void ClearLsaString(LSA_STRING *lsaStr); + +#endif diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c new file mode 100644 index 000000000..722a88158 --- /dev/null +++ b/contrib/win32/win32compat/misc.c @@ -0,0 +1,813 @@ +/* +* Author: Manoj Ampalam +* +* Copyright(c) 2016 Microsoft Corp. +* All rights reserved +* +* Misc Unix POSIX routine implementations for Windows +* +* 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 "inc\defs.h" +#include "sys\stat.h" +#include "inc\sys\statvfs.h" +#include "inc\sys\time.h" +#include +#include + +int usleep(unsigned int useconds) +{ + Sleep(useconds / 1000); + return 1; +} + +int nanosleep(const struct timespec *req, struct timespec *rem) { + HANDLE timer; + LARGE_INTEGER li; + + if (req->tv_sec < 0 || req->tv_nsec < 0 || req->tv_nsec > 999999999) { + errno = EINVAL; + return -1; + } + + if ((timer = CreateWaitableTimerW(NULL, TRUE, NULL)) == NULL) { + errno = EFAULT; + return -1; + } + + li.QuadPart = -req->tv_nsec; + if (!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)) { + CloseHandle(timer); + errno = EFAULT; + return -1; + } + + /* TODO - use wait_for_any_event, since we want to wake up on interrupts*/ + switch (WaitForSingleObject(timer, INFINITE)) { + case WAIT_OBJECT_0: + CloseHandle(timer); + return 0; + default: + errno = EFAULT; + return -1; + } +} + +/* Difference in us between UNIX Epoch and Win32 Epoch */ +#define EPOCH_DELTA_US 11644473600000000ULL + +/* This routine is contributed by * Author: NoMachine +* Copyright (c) 2009, 2010 NoMachine +* All rights reserved +*/ +int +gettimeofday(struct timeval *tv, void *tz) +{ + union + { + FILETIME ft; + unsigned long long ns; + } timehelper; + unsigned long long us; + + /* Fetch time since Jan 1, 1601 in 100ns increments */ + GetSystemTimeAsFileTime(&timehelper.ft); + + /* Convert to microseconds from 100 ns units */ + us = timehelper.ns / 10; + + /* Remove the epoch difference */ + us -= EPOCH_DELTA_US; + + /* Stuff result into the timeval */ + tv->tv_sec = (long)(us / 1000000ULL); + tv->tv_usec = (long)(us % 1000000ULL); + + return 0; +} + +void +explicit_bzero(void *b, size_t len) { + SecureZeroMemory(b, len); +} + +int statvfs(const char *path, struct statvfs *buf) { + DWORD sectorsPerCluster; + DWORD bytesPerSector; + DWORD freeClusters; + DWORD totalClusters; + + if (GetDiskFreeSpace(path, §orsPerCluster, &bytesPerSector, + &freeClusters, &totalClusters) == TRUE) + { + debug3("path : [%s]", path); + debug3("sectorsPerCluster : [%lu]", sectorsPerCluster); + debug3("bytesPerSector : [%lu]", bytesPerSector); + debug3("bytesPerCluster : [%lu]", sectorsPerCluster * bytesPerSector); + debug3("freeClusters : [%lu]", freeClusters); + debug3("totalClusters : [%lu]", totalClusters); + + buf->f_bsize = sectorsPerCluster * bytesPerSector; + buf->f_frsize = sectorsPerCluster * bytesPerSector; + buf->f_blocks = totalClusters; + buf->f_bfree = freeClusters; + buf->f_bavail = freeClusters; + buf->f_files = -1; + buf->f_ffree = -1; + buf->f_favail = -1; + buf->f_fsid = 0; + buf->f_flag = 0; + buf->f_namemax = MAX_PATH - 1; + + return 0; + } + else + { + debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", + path, GetLastError()); + + return -1; + } +} + +int fstatvfs(int fd, struct statvfs *buf) { + errno = ENOTSUP; + return -1; +} + +#include "inc\dlfcn.h" +HMODULE dlopen(const char *filename, int flags) { + return LoadLibraryA(filename); +} + +int dlclose(HMODULE handle) { + FreeLibrary(handle); + return 0; +} + +FARPROC dlsym(HMODULE handle, const char *symbol) { + return GetProcAddress(handle, symbol); +} + + +/*fopen on Windows to mimic https://linux.die.net/man/3/fopen +* only r, w, a are supported for now +*/ +FILE* +w32_fopen_utf8(const char *path, const char *mode) { + wchar_t wpath[MAX_PATH], wmode[5]; + FILE* f; + char utf8_bom[] = { 0xEF,0xBB,0xBF }; + char first3_bytes[3]; + + if (mode[1] != '\0') { + errno = ENOTSUP; + return NULL; + } + + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH) == 0 || + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 5) == 0) { + errno = EFAULT; + debug("WideCharToMultiByte failed for %c - ERROR:%d", path, GetLastError()); + return NULL; + } + + f = _wfopen(wpath, wmode); + + if (f) { + /* BOM adjustments for file streams*/ + if (mode[0] == 'w' && fseek(f, 0, SEEK_SET) != EBADF) { + /* write UTF-8 BOM - should we ?*/ + /*if (fwrite(utf8_bom, sizeof(utf8_bom), 1, f) != 1) { + fclose(f); + return NULL; + }*/ + + } + else if (mode[0] == 'r' && fseek(f, 0, SEEK_SET) != EBADF) { + /* read out UTF-8 BOM if present*/ + if (fread(first3_bytes, 3, 1, f) != 1 || + memcmp(first3_bytes, utf8_bom, 3) != 0) { + fseek(f, 0, SEEK_SET); + } + } + } + + return f; +} + + +wchar_t* +utf8_to_utf16(const char *utf8) { + int needed = 0; + wchar_t* utf16 = NULL; + if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 || + (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) + return NULL; + return utf16; +} + +char* +utf16_to_utf8(const wchar_t* utf16) { + int needed = 0; + char* utf8 = NULL; + if ((needed = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)) == 0 || + (utf8 = malloc(needed)) == NULL || + WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8, needed, NULL, NULL) == 0) + return NULL; + return utf8; +} + +static char* s_programdir = NULL; +char* w32_programdir() { + if (s_programdir != NULL) + return s_programdir; + + if ((s_programdir = utf16_to_utf8(_wpgmptr)) == NULL) + return NULL; + + /* null terminate after directory path */ + { + char* tail = s_programdir + strlen(s_programdir); + while (tail > s_programdir && *tail != '\\' && *tail != '/') + tail--; + + if (tail > s_programdir) + *tail = '\0'; + else + *tail = '.'; /* current directory */ + } + + return s_programdir; + +} + +int +daemon(int nochdir, int noclose) +{ + FreeConsole(); + return 0; +} + +int w32_ioctl(int d, int request, ...) { + va_list valist; + va_start(valist, request); + + switch (request){ + case TIOCGWINSZ: { + struct winsize* wsize = va_arg(valist, struct winsize*); + CONSOLE_SCREEN_BUFFER_INFO c_info; + if (wsize == NULL || !GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &c_info)) { + errno = EINVAL; + return -1; + } + wsize->ws_col = c_info.dwSize.X - 5; + wsize->ws_row = c_info.dwSize.Y; + wsize->ws_xpixel = 640; + wsize->ws_ypixel = 480; + return 0; + } + default: + errno = ENOTSUP; + return -1; + } +} + +HANDLE w32_fd_to_handle(int fd); +int +spawn_child(char* cmd, int in, int out, int err, DWORD flags) { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + BOOL b; + char* abs_cmd; + wchar_t * cmd_utf16; + + /* relative ? if so, add current module path to start */ + if (!(cmd && cmd[0] != '\0' && (cmd[1] == ':' || cmd[0] == '\\' || cmd[0] == '.'))) { + char* ctr; + abs_cmd = malloc(strlen(w32_programdir()) + 1 + strlen(cmd) + 1); + if (abs_cmd == NULL) { + errno = ENOMEM; + return -1; + } + ctr = abs_cmd; + memcpy(ctr, w32_programdir(), strlen(w32_programdir())); + ctr += strlen(w32_programdir()); + *ctr++ = '\\'; + memcpy(ctr, cmd, strlen(cmd) + 1); + } + else + abs_cmd = cmd; + + debug("spawning %s", abs_cmd); + + if ((cmd_utf16 = utf8_to_utf16(abs_cmd)) == NULL) { + errno = ENOMEM; + return -1; + } + + if(abs_cmd != cmd) + free(abs_cmd); + + memset(&si, 0, sizeof(STARTUPINFOW)); + si.cb = sizeof(STARTUPINFOW); + si.hStdInput = w32_fd_to_handle(in); + si.hStdOutput = w32_fd_to_handle(out); + si.hStdError = w32_fd_to_handle(err); + si.dwFlags = STARTF_USESTDHANDLES; + + b = CreateProcessW(NULL, cmd_utf16, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi); + + if (b) { + if (sw_add_child(pi.hProcess, pi.dwProcessId) == -1) { + TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hProcess); + pi.dwProcessId = -1; + } + CloseHandle(pi.hThread); + } + else { + errno = GetLastError(); + pi.dwProcessId = -1; + } + + free(cmd_utf16); + return pi.dwProcessId; +} + +void +strmode(mode_t mode, char *p) +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + //case S_IFBLK: /* block special */ + // *p++ = 'b'; + // break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + //case S_IFLNK: /* symbolic link */ + // *p++ = 'l'; + // break; +#ifdef S_IFSOCK + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#endif + case _S_IFIFO: /* fifo */ + *p++ = 'p'; + break; + default: /* unknown */ + *p++ = '?'; + break; + } + + // The below code is commented as the group, other is not applicable on the windows. + // This will be properly fixed in next releases. + // As of now we are keeping "*" for everything. + const char *permissions = "********* "; + strncpy(p, permissions, strlen(permissions) + 1); + p = p + strlen(p); + ///* usr */ + //if (mode & S_IRUSR) + // *p++ = 'r'; + //else + // *p++ = '-'; + //if (mode & S_IWUSR) + // *p++ = 'w'; + //else + // *p++ = '-'; + //switch (mode & (S_IXUSR)) { + //case 0: + // *p++ = '-'; + // break; + //case S_IXUSR: + // *p++ = 'x'; + // break; + // //case S_ISUID: + // // *p++ = 'S'; + // // break; + // //case S_IXUSR | S_ISUID: + // // *p++ = 's'; + // // break; + //} + ///* group */ + //if (mode & S_IRGRP) + // *p++ = 'r'; + //else + // *p++ = '-'; + //if (mode & S_IWGRP) + // *p++ = 'w'; + //else + // *p++ = '-'; + //switch (mode & (S_IXGRP)) { + //case 0: + // *p++ = '-'; + // break; + //case S_IXGRP: + // *p++ = 'x'; + // break; + // //case S_ISGID: + // // *p++ = 'S'; + // // break; + // //case S_IXGRP | S_ISGID: + // // *p++ = 's'; + // // break; + //} + ///* other */ + //if (mode & S_IROTH) + // *p++ = 'r'; + //else + // *p++ = '-'; + //if (mode & S_IWOTH) + // *p++ = 'w'; + //else + // *p++ = '-'; + //switch (mode & (S_IXOTH)) { + //case 0: + // *p++ = '-'; + // break; + //case S_IXOTH: + // *p++ = 'x'; + // break; + //} + //*p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} + +int +w32_chmod(const char *pathname, mode_t mode) { + /* TODO - implement this */ + errno = EOPNOTSUPP; + return -1; +} + +int +w32_chown(const char *pathname, unsigned int owner, unsigned int group) { + /* TODO - implement this */ + errno = EOPNOTSUPP; + return -1; +} + +char *realpath_win(const char *path, char resolved[MAX_PATH]); + +int +w32_utimes(const char *filename, struct timeval *tvp) { + struct utimbuf ub; + ub.actime = tvp[0].tv_sec; + ub.modtime = tvp[1].tv_sec; + int ret; + + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(filename, resolvedPathName); + wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolvedPathName); + if (resolvedPathName_utf16 == NULL) { + errno = ENOMEM; + return -1; + } + + ret = _wutime(resolvedPathName_utf16, &ub); + free(resolvedPathName_utf16); + return ret; +} + +int +w32_symlink(const char *target, const char *linkpath) { + // Not supported in windows + errno = EOPNOTSUPP; + return -1; +} + +int +link(const char *oldpath, const char *newpath) { + // Not supported in windows + errno = EOPNOTSUPP; + return -1; +} + +int +w32_rename(const char *old_name, const char *new_name) { + // Skip the first '/' in the pathname + char resolvedOldPathName[MAX_PATH]; + realpath_win(old_name, resolvedOldPathName); + + // Skip the first '/' in the pathname + char resolvedNewPathName[MAX_PATH]; + realpath_win(new_name, resolvedNewPathName); + + wchar_t *resolvedOldPathName_utf16 = utf8_to_utf16(resolvedOldPathName); + wchar_t *resolvedNewPathName_utf16 = utf8_to_utf16(resolvedNewPathName); + if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) { + errno = ENOMEM; + return -1; + } + + int returnStatus = _wrename(resolvedOldPathName_utf16, resolvedNewPathName_utf16); + free(resolvedOldPathName_utf16); + free(resolvedNewPathName_utf16); + + return returnStatus; +} + +int +w32_unlink(const char *path) { + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(path, resolvedPathName); + + wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolvedPathName); + if (NULL == resolvedPathName_utf16) { + errno = ENOMEM; + return -1; + } + + int returnStatus = _wunlink(resolvedPathName_utf16); + free(resolvedPathName_utf16); + + return returnStatus; +} + +int +w32_rmdir(const char *path) { + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(path, resolvedPathName); + + wchar_t *resolvedPathName_utf16 = utf8_to_utf16(resolvedPathName); + if (NULL == resolvedPathName_utf16) { + errno = ENOMEM; + return -1; + } + + int returnStatus = _wrmdir(resolvedPathName_utf16); + free(resolvedPathName_utf16); + + return returnStatus; +} + +int +w32_chdir(const char *dirname_utf8) { + wchar_t *dirname_utf16 = utf8_to_utf16(dirname_utf8); + if (dirname_utf16 == NULL) { + errno = ENOMEM; + return -1; + } + + int returnStatus = _wchdir(dirname_utf16); + free(dirname_utf16); + + return returnStatus; +} + +char * +w32_getcwd(char *buffer, int maxlen) { + wchar_t wdirname[MAX_PATH]; + char* putf8 = NULL; + + _wgetcwd(&wdirname[0], MAX_PATH); + + if ((putf8 = utf16_to_utf8(&wdirname[0])) == NULL) + fatal("failed to convert input arguments"); + strcpy(buffer, putf8); + free(putf8); + + return buffer; +} + +int +w32_mkdir(const char *path_utf8, unsigned short mode) { + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(path_utf8, resolvedPathName); + + wchar_t *path_utf16 = utf8_to_utf16(resolvedPathName); + if (path_utf16 == NULL) { + errno = ENOMEM; + return -1; + } + int returnStatus = _wmkdir(path_utf16); + free(path_utf16); + + return returnStatus; +} + +void +getrnd(u_char *s, size_t len) { + HCRYPTPROV hProvider; + if (CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT) == FALSE || + CryptGenRandom(hProvider, len, s) == FALSE || + CryptReleaseContext(hProvider, 0) == FALSE) + DebugBreak(); +} + +int +w32_stat(const char *path, struct w32_stat *buf) { + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(path, resolvedPathName); + + return fileio_stat(resolvedPathName, (struct _stat64*)buf); +} + +// if file is symbolic link, copy its link into "link" . +int +readlink(const char *path, char *link, int linklen) +{ + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(path, resolvedPathName); + + strcpy_s(link, linklen, resolvedPathName); + return 0; +} + +/* +* This method will expands all symbolic links and resolves references to /./, +* /../ and extra '/' characters in the null-terminated string named by +* path to produce a canonicalized absolute pathname. +*/ +char * +realpath(const char *path, char resolved[MAX_PATH]) +{ + char tempPath[MAX_PATH]; + + if ((0 == strcmp(path, "./")) || (0 == strcmp(path, "."))) { + tempPath[0] = '/'; + _getcwd(&tempPath[1], sizeof(tempPath) - 1); + slashconvert(tempPath); + + strncpy(resolved, tempPath, strlen(tempPath) + 1); + return resolved; + } + + if (path[0] != '/') + strlcpy(resolved, path, sizeof(tempPath)); + else + strlcpy(resolved, path + 1, sizeof(tempPath)); + + backslashconvert(resolved); + PathCanonicalizeA(tempPath, resolved); + slashconvert(tempPath); + + // Store terminating slash in 'X:/' on Windows. + if (tempPath[1] == ':' && tempPath[2] == 0) { + tempPath[2] = '/'; + tempPath[3] = 0; + } + + resolved[0] = '/'; // will be our first slash in /x:/users/test1 format + strncpy(resolved + 1, tempPath, sizeof(tempPath) - 1); + return resolved; +} + +// like realpathWin32() but takes out the first slash so that windows systems can work on the actual file or directory +char * +realpath_win(const char *path, char resolved[MAX_PATH]) +{ + char tempPath[MAX_PATH]; + realpath(path, tempPath); + + strncpy(resolved, &tempPath[1], sizeof(tempPath) - 1); + return resolved; +} + +// Maximum reparse buffer info size. The max user defined reparse +// data is 16KB, plus there's a header. +#define MAX_REPARSE_SIZE 17000 +#define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) // winnt ntifs +#define IO_REPARSE_TAG_HSM (0xC0000004L) // winnt ntifs +#define IO_REPARSE_TAG_SIS (0x80000007L) // winnt ntifs +#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 + + +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +BOOL +ResolveLink(wchar_t * tLink, wchar_t *ret, DWORD * plen, DWORD Flags) +{ + HANDLE fileHandle; + BYTE reparseBuffer[MAX_REPARSE_SIZE]; + PBYTE reparseData; + PREPARSE_GUID_DATA_BUFFER reparseInfo = (PREPARSE_GUID_DATA_BUFFER)reparseBuffer; + PREPARSE_DATA_BUFFER msReparseInfo = (PREPARSE_DATA_BUFFER)reparseBuffer; + DWORD returnedLength; + + if (Flags & FILE_ATTRIBUTE_DIRECTORY) + { + fileHandle = CreateFileW(tLink, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); + + } + else { + + // + // Open the file + // + fileHandle = CreateFileW(tLink, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, 0); + } + if (fileHandle == INVALID_HANDLE_VALUE) + { + swprintf_s(ret, *plen, L"%ls", tLink); + return TRUE; + } + + if (GetFileAttributesW(tLink) & FILE_ATTRIBUTE_REPARSE_POINT) { + + if (DeviceIoControl(fileHandle, FSCTL_GET_REPARSE_POINT, + NULL, 0, reparseInfo, sizeof(reparseBuffer), + &returnedLength, NULL)) { + + if (IsReparseTagMicrosoft(reparseInfo->ReparseTag)) { + + switch (reparseInfo->ReparseTag) { + case 0x80000000 | IO_REPARSE_TAG_SYMBOLIC_LINK: + case IO_REPARSE_TAG_MOUNT_POINT: + if (*plen >= msReparseInfo->MountPointReparseBuffer.SubstituteNameLength) + { + reparseData = (PBYTE)&msReparseInfo->SymbolicLinkReparseBuffer.PathBuffer; + WCHAR temp[1024]; + wcsncpy_s(temp, 1024, + (PWCHAR)(reparseData + msReparseInfo->MountPointReparseBuffer.SubstituteNameOffset), + (size_t)msReparseInfo->MountPointReparseBuffer.SubstituteNameLength); + temp[msReparseInfo->MountPointReparseBuffer.SubstituteNameLength] = 0; + swprintf_s(ret, *plen, L"%ls", &temp[4]); + } + else + { + swprintf_s(ret, *plen, L"%ls", tLink); + return FALSE; + } + + break; + default: + break; + } + } + } + } + else { + swprintf_s(ret, *plen, L"%ls", tLink); + } + + CloseHandle(fileHandle); + return TRUE; +} \ No newline at end of file diff --git a/contrib/win32/win32compat/no-ops.c b/contrib/win32/win32compat/no-ops.c new file mode 100644 index 000000000..6fa5b1c03 --- /dev/null +++ b/contrib/win32/win32compat/no-ops.c @@ -0,0 +1,129 @@ +/* +* Author: Manoj Ampalam +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Definitions of all SSH/POSIX calls that are otherwise no-ops in Windows +* +* 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 "inc\sys\param.h" + +/* uuidswap.c defs */ +void temporarily_use_uid(struct passwd *pw){ + return; +} + +void +permanently_drop_suid(uid_t uid) { + return; +} + +void +restore_uid(void) { + return; +} + +void +permanently_set_uid(struct passwd *pw) { + return; +} + + +/* mux.c defs */ +int muxserver_sock = -1; +typedef struct Channel Channel; +unsigned int muxclient_command = 0; +void +muxserver_listen(void){ + return; +} + +void +mux_exit_message(Channel *c, int exitval) { + return; +} + +void +mux_tty_alloc_failed(Channel *c) { + return; +} + +void +muxclient(const char *path) { + return; +} + + +int +innetgr(const char *netgroup, const char *host, + const char *user, const char *domain) { + return -1; +} + + +/* groupaccess.c*/ +int +ga_init(const char *user, gid_t base) { + return -1; +} + +int +ga_match(char * const *groups, int n) { + return -1; +} + +int +ga_match_pattern_list(const char *group_pattern) { + return -1; +} + +void +ga_free(void) { + return; +} + +int chroot(const char *path) { + return -1; +} + +int initgroups(const char *user, gid_t group) { + return -1; +} + + +/* sshd.c */ +int +setgroups(gid_t group, char* name) { + return 0; +} + +int +setsid(void) { + return 0; +} + +int startup_handler(void) { + return 0; +} diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c new file mode 100644 index 000000000..b779f554b --- /dev/null +++ b/contrib/win32/win32compat/pwd.c @@ -0,0 +1,298 @@ +/* + * Author: NoMachine + * + * Copyright (c) 2009, 2011 NoMachine + * All rights reserved + * + * Support functions and system calls' replacements needed to let the + * software run on Win32 based operating systems. + * + * 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 +#define SECURITY_WIN32 +#include +#include "inc\pwd.h" +#include "inc\grp.h" +#include "inc\utf.h" + +static struct passwd pw; +static char* pw_shellpath = NULL; +#define SHELL_HOST "\\ssh-shellhost.exe" + +char* w32_programdir(); + +int +initialize_pw() { + if (pw_shellpath == NULL) { + if ((pw_shellpath = malloc(strlen(w32_programdir()) + strlen(SHELL_HOST) + 1)) == NULL) + fatal("initialize_pw - out of memory"); + else { + char* head = pw_shellpath; + memcpy(head, w32_programdir(), strlen(w32_programdir())); + head += strlen(w32_programdir()); + memcpy(head, SHELL_HOST, strlen(SHELL_HOST)); + head += strlen(SHELL_HOST); + *head = '\0'; + } + } + if (pw.pw_shell != pw_shellpath) { + memset(&pw, 0, sizeof(pw)); + pw.pw_shell = pw_shellpath; + pw.pw_passwd = "\0"; + /* pw_uid = 0 for root on Unix and SSH code has specific restrictions for root + * that are not applicable in Windows */ + pw.pw_uid = 1; + } + return 0; +} + +void +reset_pw() { + initialize_pw(); + if (pw.pw_name) + free(pw.pw_name); + if (pw.pw_dir) + free(pw.pw_dir); +} + +static struct passwd* +get_passwd(const char *user_utf8, LPWSTR user_sid) { + struct passwd *ret = NULL; + wchar_t *user_utf16 = NULL, *uname_utf16, *udom_utf16, *tmp; + char *uname_utf8 = NULL, *pw_home_utf8 = NULL; + LPBYTE user_info = NULL; + LPWSTR user_sid_local = NULL; + wchar_t reg_path[MAX_PATH], profile_home[MAX_PATH]; + HKEY reg_key = 0; + int tmp_len = MAX_PATH; + PDOMAIN_CONTROLLER_INFOW pdc = NULL; + + errno = 0; + + reset_pw(); + + if ((user_utf16 = utf8_to_utf16(user_utf8) ) == NULL) { + errno = ENOMEM; + goto done; + } + + /*find domain part if any*/ + if ((tmp = wcschr(user_utf16, L'\\')) != NULL) { + udom_utf16 = user_utf16; + uname_utf16 = tmp + 1; + *tmp = L'\0'; + + } + else if ((tmp = wcschr(user_utf16, L'@')) != NULL) { + udom_utf16 = tmp + 1; + uname_utf16 = user_utf16; + *tmp = L'\0'; + } + else { + uname_utf16 = user_utf16; + udom_utf16 = NULL; + } + + if (user_sid == NULL) { + if (NetUserGetInfo(udom_utf16, uname_utf16, 23, &user_info) != NERR_Success) { + if (DsGetDcNameW(NULL, udom_utf16, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdc) == ERROR_SUCCESS) { + if (NetUserGetInfo(pdc->DomainControllerName, uname_utf16, 23, &user_info) != NERR_Success || + ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { + errno = ENOMEM; //?? + goto done; + } + } + else { + errno = ENOMEM; //?? + goto done; + } + } + else { + if (ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { + errno = ENOMEM; //?? + goto done; + } + } + user_sid = user_sid_local; + } + + if (swprintf(reg_path, MAX_PATH, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", user_sid) == MAX_PATH || + RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®_key) != 0 || + RegQueryValueExW(reg_key, L"ProfileImagePath", 0, NULL, (LPBYTE)profile_home, &tmp_len) != 0) + GetWindowsDirectoryW(profile_home, MAX_PATH); + + if ((uname_utf8 = _strdup(user_utf8)) == NULL || + (pw_home_utf8 = utf16_to_utf8(profile_home)) == NULL) { + errno = ENOMEM; + goto done; + } + + pw.pw_name = uname_utf8; + uname_utf8 = NULL; + pw.pw_dir = pw_home_utf8; + pw_home_utf8 = NULL; + ret = &pw; +done: + if (user_utf16) + free(user_utf16); + if (uname_utf8) + free(uname_utf8); + if (pw_home_utf8) + free(pw_home_utf8); + if (user_info) + NetApiBufferFree(user_info); + if (user_sid_local) + LocalFree(user_sid_local); + if (reg_key) + RegCloseKey(reg_key); + if (pdc) + NetApiBufferFree(pdc); + return ret; +} + +struct passwd* +w32_getpwnam(const char *user_utf8) { + return get_passwd(user_utf8, NULL); +} + +struct passwd* +w32_getpwuid(uid_t uid) { + wchar_t* wuser = NULL; + char* user_utf8 = NULL; + ULONG needed = 0; + struct passwd *ret = NULL; + HANDLE token = 0; + DWORD info_len = 0; + TOKEN_USER* info = NULL; + LPWSTR user_sid = NULL; + + errno = 0; + + if (GetUserNameExW(NameSamCompatible, NULL, &needed) != 0 || + (wuser = malloc(needed * sizeof(wchar_t))) == NULL || + GetUserNameExW(NameSamCompatible, wuser, &needed) == 0 || + (user_utf8 = utf16_to_utf8(wuser)) == NULL || + OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == FALSE || + GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || + (info = (TOKEN_USER*)malloc(info_len)) == NULL || + GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE || + ConvertSidToStringSidW(info->User.Sid, &user_sid) == FALSE){ + errno = ENOMEM; + goto done; + } + ret = get_passwd(user_utf8, user_sid); + +done: + if (wuser) + free(wuser); + if (user_utf8) + free(user_utf8); + if (token) + CloseHandle(token); + if (info) + free(info); + if (user_sid) + LocalFree(user_sid); + return ret; +} + + + +char *group_from_gid(gid_t gid, int nogroup) { + return "-"; +} + +char *user_from_uid(uid_t uid, int nouser) { + return "-"; +} + + +/* TODO - this is moved from realpath.c in openbsdcompat. Review and finalize its position*/ + +#include + +void backslashconvert(char *str) +{ + while (*str) { + if (*str == '/') + *str = '\\'; // convert forward slash to back slash + str++; + } + +} + +// convert back slash to forward slash +void slashconvert(char *str) +{ + while (*str) { + if (*str == '\\') + *str = '/'; // convert back slash to forward slash + str++; + } +} + + +uid_t +getuid(void) { + return 0; +} + +gid_t +getgid(void) { + return 0; +} + +uid_t +geteuid(void) { + return 0; +} + +gid_t +getegid(void) { + return 0; +} + +int +setuid(uid_t uid) { + return 0; +} + +int +setgid(gid_t gid) { + return 0; +} + +int +seteuid(uid_t uid) { + return 0; +} + +int +setegid(gid_t gid) { + return 0; +} diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c new file mode 100644 index 000000000..dfd052951 --- /dev/null +++ b/contrib/win32/win32compat/shell-host.c @@ -0,0 +1,1307 @@ +/* +* Author: Manoj Ampalam +* Primitive shell-host to support parsing of cmd.exe input and async IO redirection +* +* Author: Ray Heyes +* PTY with ANSI emulation wrapper +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 + +#define MAX_CONSOLE_COLUMNS 9999 +#define MAX_CONSOLE_ROWS 9999 +#define MAX_CMD_LEN 8191 // msdn +#define WM_APPEXIT WM_USER+1 +#define MAX_EXPECTED_BUFFER_SIZE 1024 + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 +#endif + +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif + +typedef BOOL (WINAPI *__t_SetCurrentConsoleFontEx)( + _In_ HANDLE hConsoleOutput, + _In_ BOOL bMaximumWindow, + _In_ PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx + ); +__t_SetCurrentConsoleFontEx __SetCurrentConsoleFontEx; + +typedef BOOL (WINAPI *__t_UnhookWinEvent)( + _In_ HWINEVENTHOOK hWinEventHook + ); +__t_UnhookWinEvent __UnhookWinEvent; + +typedef HWINEVENTHOOK (WINAPI *__t_SetWinEventHook)( + _In_ UINT eventMin, + _In_ UINT eventMax, + _In_ HMODULE hmodWinEventProc, + _In_ WINEVENTPROC lpfnWinEventProc, + _In_ DWORD idProcess, + _In_ DWORD idThread, + _In_ UINT dwflags + ); +__t_SetWinEventHook __SetWinEventHook; + + +typedef struct consoleEvent { + DWORD event; + HWND hwnd; + LONG idObject; + LONG idChild; + void* prior; + void* next; +} consoleEvent; + +struct key_translation +{ + char incoming[5]; + int vk; + char outgoing[1]; +} key_translation; + +struct key_translation keys[] = { + { "\x1b", VK_ESCAPE, "\x1b" }, + { "\r", VK_RETURN, "\r" }, + { "\b", VK_BACK, "\b" }, + { "\x7f", VK_BACK, "\x7f" }, + { "\t", VK_TAB, "\t" }, + { "\x1b[A", VK_UP, 0 }, + { "\x1b[B", VK_DOWN, 0 }, + { "\x1b[C", VK_RIGHT, 0 }, + { "\x1b[D", VK_LEFT, 0 }, + { "\x1b[1~", VK_HOME, 0 }, + { "\x1b[2~", VK_INSERT, 0 }, + { "\x1b[3~", VK_DELETE, 0 }, + { "\x1b[4~", VK_END, 0 }, + { "\x1b[5~", VK_PRIOR, 0 }, + { "\x1b[6~", VK_NEXT, 0 }, + { "\x1b[11~", VK_F1, 0 }, + { "\x1b[12~", VK_F2, 0 }, + { "\x1b[13~", VK_F3, 0 }, + { "\x1b[14~", VK_F4, 0 }, + { "\x1b[15~", VK_F5, 0 }, + { "\x1b[17~", VK_F6, 0 }, + { "\x1b[18~", VK_F7, 0 }, + { "\x1b[19~", VK_F8, 0 }, + { "\x1b[20~", VK_F9, 0 }, + { "\x1b[21~", VK_F10, 0 }, + { "\x1b[23~", VK_F11, 0 }, + { "\x1b[24~", VK_F12, 0 } +}; + +consoleEvent* head = NULL; +consoleEvent* tail = NULL; + +BOOL bRet = FALSE; +BOOL bNoScrollRegion = FALSE; +BOOL bStartup = TRUE; +BOOL bAnsi = FALSE; +BOOL bHookEvents = FALSE; + +HANDLE child_out = INVALID_HANDLE_VALUE; +HANDLE child_in = INVALID_HANDLE_VALUE; +HANDLE child_err = INVALID_HANDLE_VALUE; +HANDLE pipe_in = INVALID_HANDLE_VALUE; +HANDLE pipe_out = INVALID_HANDLE_VALUE; +HANDLE pipe_err = INVALID_HANDLE_VALUE; +HANDLE child = INVALID_HANDLE_VALUE; +HANDLE hConsoleBuffer = INVALID_HANDLE_VALUE; + +HANDLE monitor_thread = INVALID_HANDLE_VALUE; +HANDLE io_thread = INVALID_HANDLE_VALUE; +HANDLE ux_thread = INVALID_HANDLE_VALUE; + +DWORD hostProcessId = 0; +DWORD hostThreadId = 0; +DWORD childProcessId = 0; +DWORD dwStatus = 0; +DWORD currentLine = 0; +DWORD lastLineLength = 0; + +UINT cp = 0; + +UINT ViewPortY = 0; +UINT lastViewPortY = 0; + +BOOL bFullScreen = FALSE; +BOOL bUseAnsiEmulation = TRUE; + +UINT savedViewPortY = 0; +UINT savedLastViewPortY = 0; + +DWORD in_cmd_len = 0; +char in_cmd[MAX_CMD_LEN]; + +CRITICAL_SECTION criticalSection; + +CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo; +CONSOLE_SCREEN_BUFFER_INFOEX nextConsoleInfo; +STARTUPINFO inputSi; + +#define GOTO_CLEANUP_ON_FALSE(exp) do { \ + ret = (exp); \ + if (ret == FALSE) \ + goto cleanup; \ +} while(0) \ + +#define GOTO_CLEANUP_ON_ERR(exp) do { \ + if ((exp) != 0) \ + goto cleanup; \ +} while(0) \ + +// Console keystroke handling +void SendKeyStroke(HANDLE hInput, int keyStroke, char character) +{ + DWORD wr = 0; + INPUT_RECORD ir; + + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = TRUE; + ir.Event.KeyEvent.wRepeatCount = 1; + ir.Event.KeyEvent.wVirtualKeyCode = keyStroke; + ir.Event.KeyEvent.wVirtualScanCode = 0; + ir.Event.KeyEvent.dwControlKeyState = 0; + ir.Event.KeyEvent.uChar.UnicodeChar = 0; + if(character != 0) + ir.Event.KeyEvent.uChar.AsciiChar = character; + + WriteConsoleInputA(hInput, &ir, 1, &wr); + + ir.Event.KeyEvent.bKeyDown = FALSE; + WriteConsoleInputA(hInput, &ir, 1, &wr); +} + +void ProcessIncomingKeys(char * ansikey) { + int nKey = 0; + int index = ARRAYSIZE(keys); + + while (nKey < index) { + if (strcmp(ansikey, keys[nKey].incoming) == 0) { + SendKeyStroke(child_in, keys[nKey].vk, keys[nKey].outgoing[0]); + break; + } + else + nKey++; + } + + if (nKey == index) { + SendKeyStroke(child_in, 0, ansikey[0]); + } +} + +// VT output routines +void SendLF(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\n", 1, &wr, NULL); +} + +void SendClearScreen(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[2J", 4, &wr, NULL); +} + +void SendClearScreenFromCursor(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[1J", 4, &wr, NULL); +} + +void SendHideCursor(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[?25l", 6, &wr, NULL); +} + +void SendShowCursor(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[?25h", 6, &wr, NULL); +} + +void SendCursorPositionRequest(HANDLE hInput) { + DWORD wr = 0; + + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[6n", 4, &wr, NULL); +} + +void SendSetCursor(HANDLE hInput, int X, int Y) { + + DWORD wr = 0; + DWORD out = 0; + + char formatted_output[255]; + + out = _snprintf_s(formatted_output, sizeof(formatted_output), _TRUNCATE, "\033[%d;%dH", Y, X); + if (bUseAnsiEmulation) + WriteFile(hInput, formatted_output, out, &wr, NULL); +} + +void SendVerticalScroll(HANDLE hInput, int lines) { + + DWORD wr = 0; + DWORD out = 0; + char formatted_output[255]; + + LONG vn = abs(lines); + + if (lines > 0) { + + out = snprintf(formatted_output, sizeof(formatted_output), "\033[%dT", vn); + + if (bUseAnsiEmulation) + WriteFile(hInput, formatted_output, out, &wr, NULL); + } + // Not supporting the [S at the moment. +} + +void SendHorizontalScroll(HANDLE hInput, int cells) { + + DWORD wr = 0; + DWORD out = 0; + char formatted_output[255]; + + out = snprintf(formatted_output, sizeof(formatted_output), "\033[%dG", cells); + + if (bUseAnsiEmulation) + WriteFile(hInput, formatted_output, out, &wr, NULL); +} + +void SendCharacter(HANDLE hInput, WORD attributes, wchar_t character) { + + DWORD wr = 0; + DWORD out = 0; + DWORD current = 0; + + char formatted_output[2048]; + + static WORD pattributes = 0; + + USHORT Color = 0; + ULONG Status = 0; + + PSTR Next; + size_t SizeLeft; + + if (!character) + return; + + Next = formatted_output; + SizeLeft = sizeof formatted_output; + + // + // Handle the foreground intensity + // + if ((attributes & FOREGROUND_INTENSITY) != 0) { + Color = 1; + } + else { + Color = 0; + } + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, "\033[%u", Color); + + // + // Handle the background intensity + // + if ((attributes & BACKGROUND_INTENSITY) != 0) { + Color = 1; + } + else { + Color = 39; + } + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); + + // + // Handle the underline + // + if ((attributes & COMMON_LVB_UNDERSCORE) != 0) { + Color = 4; + } + else { + Color = 24; + } + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); + + // + // Handle reverse video + // + if ((attributes & COMMON_LVB_REVERSE_VIDEO) != 0) { + Color = 7; + } + else { + Color = 27; + } + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); + + // + // Add background and foreground colors to buffer. + // + Color = 30 + + 4 * ((attributes & FOREGROUND_BLUE) != 0) + + 2 * ((attributes & FOREGROUND_GREEN) != 0) + + 1 * ((attributes & FOREGROUND_RED) != 0); + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); + + Color = 40 + + 4 * ((attributes & BACKGROUND_BLUE) != 0) + + 2 * ((attributes & BACKGROUND_GREEN) != 0) + + 1 * ((attributes & BACKGROUND_RED) != 0); + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); + + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, "m", Color); + + if (bUseAnsiEmulation && attributes != pattributes) + WriteFile(hInput, formatted_output, (Next - formatted_output), &wr, NULL); + + // East asian languages have 2 bytes for each character, only use the first + if (!(attributes & COMMON_LVB_TRAILING_BYTE)) + { + int nSize = WideCharToMultiByte(CP_UTF8, + 0, + &character, + 1, + Next, + 10, + NULL, + NULL); + + if(nSize > 0) + WriteFile(hInput, Next, nSize, &wr, NULL); + } + + pattributes = attributes; +} + +void SendBuffer(HANDLE hInput, CHAR_INFO *buffer, DWORD bufferSize) { + + if (bufferSize <= 0) + return; + + for (DWORD i = 0; i < bufferSize; i++) + { + SendCharacter(hInput, buffer[i].Attributes, buffer[i].Char.UnicodeChar); + } +} + +void CalculateAndSetCursor(HANDLE hInput, UINT aboveTopLine, UINT viewPortHeight, UINT x, UINT y) { + + SendSetCursor(pipe_out, x + 1, y + 1); + currentLine = y; +} + +void SizeWindow(HANDLE hInput) { + + SMALL_RECT srWindowRect; + COORD coordScreen; + BOOL bSuccess = FALSE; + + // The input window does not scroll currently to ease calculations + // on the paint/draw. + bNoScrollRegion = TRUE; + + // Set the default font to Consolas + CONSOLE_FONT_INFOEX matchingFont; + matchingFont.cbSize = sizeof(matchingFont); + matchingFont.nFont = 0; + matchingFont.dwFontSize.X = 0; + matchingFont.dwFontSize.Y = 16; + matchingFont.FontFamily = FF_DONTCARE; + matchingFont.FontWeight = FW_NORMAL; + wcscpy(matchingFont.FaceName, L"Consolas"); + + bSuccess = __SetCurrentConsoleFontEx(child_out, FALSE, &matchingFont); + + // This information is the live screen + ZeroMemory(&consoleInfo, sizeof(consoleInfo)); + consoleInfo.cbSize = sizeof(consoleInfo); + + bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + + // Get the largest size we can size the console window to. + coordScreen = GetLargestConsoleWindowSize(child_out); + + // Define the new console window size and scroll position. + if (inputSi.dwXCountChars == 0 || inputSi.dwYCountChars == 0) { + inputSi.dwXCountChars = 80; + inputSi.dwYCountChars = 25; + } + + srWindowRect.Right = (SHORT)(min(inputSi.dwXCountChars, coordScreen.X) - 1); + srWindowRect.Bottom = (SHORT)(min(inputSi.dwYCountChars, coordScreen.Y) - 1); + srWindowRect.Left = srWindowRect.Top = (SHORT)0; + + /// Define the new console buffer size to be the maximum possible. + coordScreen.X = 100; + coordScreen.Y = 9999; + + if (SetConsoleWindowInfo(child_out, TRUE, &srWindowRect)) { + + bSuccess = SetConsoleScreenBufferSize(child_out, coordScreen); + } + else { + if (SetConsoleScreenBufferSize(child_out, coordScreen)) { + + bSuccess = SetConsoleWindowInfo(child_out, TRUE, &srWindowRect); + } + + } + + bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); +} + +// End of VT output routines + +DWORD WINAPI MonitorChild(_In_ LPVOID lpParameter) { + WaitForSingleObject(child, INFINITE); + PostThreadMessage(hostThreadId, WM_APPEXIT, 0, 0); + return 0; +} + +DWORD ProcessEvent(void *p) { + + char f[255]; + wchar_t chUpdate; + + WORD wAttributes; + WORD wX; + WORD wY; + + DWORD dwProcessId; + DWORD wr = 0; + DWORD dwMode; + + DWORD event; + HWND hwnd; + LONG idObject; + LONG idChild; + + if (!p) + { + return ERROR_INVALID_PARAMETER; + } + + consoleEvent* current = (consoleEvent *)p; + + if(current) { + event = current->event; + hwnd = current->hwnd; + idObject = current->idObject; + idChild = current->idChild; + } + else { + return ERROR_INVALID_PARAMETER; + } + + if (event < EVENT_CONSOLE_CARET || event > EVENT_CONSOLE_LAYOUT) + { + return ERROR_INVALID_PARAMETER; + } + + if (child_out == INVALID_HANDLE_VALUE || child_out == NULL) + { + return ERROR_INVALID_PARAMETER; + } + + GetWindowThreadProcessId(hwnd, &dwProcessId); + + if (childProcessId != dwProcessId) + { + return ERROR_SUCCESS; + } + + ZeroMemory(&consoleInfo, sizeof(consoleInfo)); + consoleInfo.cbSize = sizeof(consoleInfo); + + GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + + UINT viewPortHeight = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + UINT viewPortWidth = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + + switch (event) { + case EVENT_CONSOLE_CARET: + { + COORD co; + + if (idObject == CONSOLE_CARET_SELECTION) { + co.X = HIWORD(idChild); + co.Y = LOWORD(idChild); + } + else { + co.X = HIWORD(idChild); + co.Y = LOWORD(idChild); + } + + break; + } + case EVENT_CONSOLE_UPDATE_REGION: + { + SMALL_RECT readRect; + + readRect.Top = HIWORD(idObject); + readRect.Left = LOWORD(idObject); + readRect.Bottom = HIWORD(idChild); + readRect.Right = LOWORD(idChild); + + // Detect a "cls" (Windows). + if (!bStartup && + (readRect.Top == consoleInfo.srWindow.Top || readRect.Top == nextConsoleInfo.srWindow.Top)) + { + BOOL isClearCommand = FALSE; + isClearCommand = (consoleInfo.dwSize.X == readRect.Right + 1) && (consoleInfo.dwSize.Y == readRect.Bottom + 1); + + // If cls then inform app to clear its buffers and return. + if (isClearCommand) + { + SendClearScreen(pipe_out); + ViewPortY = 0; + lastViewPortY = 0; + + return ERROR_SUCCESS; + } + } + + // Figure out the buffer size + COORD coordBufSize; + coordBufSize.Y = readRect.Bottom - readRect.Top + 1; + coordBufSize.X = readRect.Right - readRect.Left + 1; + + // Security check: the maximum screen buffer size is 9999 columns x 9999 lines so check + // the computed buffer size for overflow. since the X and Y in the COORD structure + // are shorts they could be negative. + if (coordBufSize.X < 0 || coordBufSize.X > MAX_CONSOLE_COLUMNS || + coordBufSize.Y < 0 || coordBufSize.Y > MAX_CONSOLE_ROWS) + { + return ERROR_INVALID_PARAMETER; + } + + // Compute buffer size + DWORD bufferSize = coordBufSize.X * coordBufSize.Y; + + if (bufferSize > MAX_EXPECTED_BUFFER_SIZE) { + + if (!bStartup) { + SendClearScreen(pipe_out); + ViewPortY = 0; + lastViewPortY = 0; + } + + return ERROR_SUCCESS; + } + + // Create the screen scrape buffer + CHAR_INFO *pBuffer = (PCHAR_INFO)malloc(sizeof(CHAR_INFO) * bufferSize); + + if (!pBuffer) + { + return ERROR_INSUFFICIENT_BUFFER; + } + + // The top left destination cell of the temporary buffer is row 0, col 0. + COORD coordBufCoord; + coordBufCoord.X = 0; + coordBufCoord.Y = 0; + + // Copy the block from the screen buffer to the temp. buffer. + if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect)) + { + DWORD dwError = GetLastError(); + + free(pBuffer); + return dwError; + } + + if (readRect.Top > currentLine) + for(SHORT n = currentLine; n < readRect.Top; n++) + SendLF(pipe_out); + + // Set cursor location based on the reported location from the message. + CalculateAndSetCursor(pipe_out, ViewPortY, viewPortHeight, readRect.Left, + readRect.Top); + + // Send the entire block. + SendBuffer(pipe_out, pBuffer, bufferSize); + + lastViewPortY = ViewPortY; + lastLineLength = readRect.Left; + + free(pBuffer); + + break; + } + case EVENT_CONSOLE_UPDATE_SIMPLE: + { + chUpdate = LOWORD(idChild); + wAttributes = HIWORD(idChild); + wX = LOWORD(idObject); + wY = HIWORD(idObject); + + // Set cursor location based on the reported location from the message. + CalculateAndSetCursor(pipe_out, ViewPortY, viewPortHeight, wX, wY); + + // Send the one character. Note that a CR doesn't end up here. + SendCharacter(pipe_out, wAttributes, chUpdate); + + break; + } + case EVENT_CONSOLE_UPDATE_SCROLL: + { + DWORD out = 0; + LONG vd = idChild; + LONG hd = idObject; + + LONG vn = abs(vd); + + if (vd > 0) { + if(ViewPortY > 0) + ViewPortY -= vn; + } + else { + ViewPortY += vn; + } + + break; + } + case EVENT_CONSOLE_LAYOUT: + { + if (consoleInfo.dwMaximumWindowSize.X == consoleInfo.dwSize.X && + consoleInfo.dwMaximumWindowSize.Y == consoleInfo.dwSize.Y && + (consoleInfo.dwCursorPosition.X == 0 && consoleInfo.dwCursorPosition.Y == 0)) + { + // Screen has switched to fullscreen mode + SendClearScreen(pipe_out); + + savedViewPortY = ViewPortY; + savedLastViewPortY = lastViewPortY; + + ViewPortY = 0; + lastViewPortY = 0;; + + bFullScreen = TRUE; + } + else + { + // Leave full screen mode if applicable + if (bFullScreen) { + SendClearScreen(pipe_out); + + ViewPortY = savedViewPortY; + lastViewPortY = savedLastViewPortY; + bFullScreen = FALSE; + } + } + + break; + } + } + + ZeroMemory(&consoleInfo, sizeof(consoleInfo)); + consoleInfo.cbSize = sizeof(consoleInfo); + + GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + + return ERROR_SUCCESS; +} + +DWORD WINAPI ProcessEventQueue(LPVOID p) { + + static SHORT lastX = 0; + static SHORT lastY = 0; + + while (1) { + + while (head) { + + EnterCriticalSection(&criticalSection); + + consoleEvent* current = head; + + if (current) { + if (current->next) + { + head = current->next; + head->prior = NULL; + } + else + { + head = NULL; + tail = NULL; + } + } + + LeaveCriticalSection(&criticalSection); + + if (current) + { + ProcessEvent(current); + free(current); + } + } + + if (child_in != INVALID_HANDLE_VALUE && child_in != NULL && + child_out != INVALID_HANDLE_VALUE && child_out != NULL) + { + DWORD dwInputMode; + DWORD dwOutputMode; + + if (GetConsoleMode(child_in, &dwInputMode) && GetConsoleMode(child_out, &dwOutputMode)) { + if (((dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING) && + ((dwInputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) == ENABLE_VIRTUAL_TERMINAL_INPUT)) + { + bAnsi = TRUE; + } + else { + bAnsi = FALSE; + } + } + + ZeroMemory(&consoleInfo, sizeof(consoleInfo)); + consoleInfo.cbSize = sizeof(consoleInfo); + + // This information is the live buffer that's currently in use. + GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + + // Set the cursor to the last known good location according to the live buffer. + if (lastX != consoleInfo.dwCursorPosition.X || + lastY != consoleInfo.dwCursorPosition.Y) { + + SendSetCursor(pipe_out, consoleInfo.dwCursorPosition.X + 1, + consoleInfo.dwCursorPosition.Y + 1); + } + + lastX = consoleInfo.dwCursorPosition.X; + lastY = consoleInfo.dwCursorPosition.Y; + } + + Sleep(100); + } + + return 0; +} + +void QueueEvent( + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild) { + + consoleEvent* current = NULL; + + EnterCriticalSection(&criticalSection); + + current = malloc(sizeof(consoleEvent)); + + if (current) { + if (!head) { + current->event = event; + current->hwnd = hwnd; + current->idChild = idChild; + current->idObject = idObject; + + // No links head == tail + current->next = NULL; + current->prior = NULL; + + head = current; + tail = current; + } + else { + current->event = event; + current->hwnd = hwnd; + current->idChild = idChild; + current->idObject = idObject; + + // Current tail points to new tail + tail->next = current; + + // New tail points to old tail + current->prior = tail; + current->next = NULL; + + // Update the tail pointer to the new + // last event + tail = current; + } + } + + LeaveCriticalSection(&criticalSection); + + return; +} + +DWORD WINAPI ProcessPipes(LPVOID p) { + + BOOL ret; + DWORD dwStatus; + + /* process data from pipe_in and route appropriately */ + while (1) { + char buf[128]; + ZeroMemory(buf, 128); + + DWORD rd = 0, wr = 0, i = -1; + + GOTO_CLEANUP_ON_FALSE(ReadFile(pipe_in, buf, 128, &rd, NULL)); + + bStartup = FALSE; + + while (++i < rd) { + + INPUT_RECORD ir; + + if (buf[i] == 3) {/*Ctrl+C - Raise Ctrl+C*/ + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + continue; + } + + if (bAnsi) { + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = TRUE; + ir.Event.KeyEvent.wRepeatCount = 1; + ir.Event.KeyEvent.wVirtualKeyCode = 0; + ir.Event.KeyEvent.wVirtualScanCode = 0; + ir.Event.KeyEvent.uChar.AsciiChar = buf[i]; + ir.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputA(child_in, &ir, 1, &wr); + + ir.Event.KeyEvent.bKeyDown = FALSE; + WriteConsoleInputA(child_in, &ir, 1, &wr); + } + else { + ProcessIncomingKeys(buf); + break; + } + } + } + +cleanup: + dwStatus = GetLastError(); + + return 0; +} + +void CALLBACK ConsoleEventProc(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime) +{ + QueueEvent(event, hwnd, idObject, idChild); +} + +DWORD ProcessMessages(void* p) +{ + BOOL ret; + DWORD dwMode; + DWORD dwStatus; + SECURITY_ATTRIBUTES sa; + MSG msg; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + while (child_in == (HANDLE)-1) + { + child_in = CreateFile(TEXT("CONIN$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); + } + + if (child_in == (HANDLE)-1) + goto cleanup; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + while (child_out == (HANDLE)-1) + { + child_out = CreateFile(TEXT("CONOUT$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); + } + + if (child_out == (HANDLE)-1) + goto cleanup; + + child_err = child_out; + + SizeWindow(child_out); + + // Get the current buffer information after all the adjustments. + GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + + // Loop for the console output events + while (GetMessage(&msg, NULL, 0, 0)) + { + if (msg.message == WM_APPEXIT) + { + break; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + +cleanup: + dwStatus = GetLastError(); + + if (child_in != INVALID_HANDLE_VALUE) + CloseHandle(child_in); + if (child_out != INVALID_HANDLE_VALUE) + CloseHandle(child_out); + return 0; +} + +int start_with_pty(int ac, wchar_t **av) { + STARTUPINFO si; + PROCESS_INFORMATION pi; + wchar_t cmd[MAX_CMD_LEN]; + SECURITY_ATTRIBUTES sa; + BOOL ret; + DWORD dwThreadId; + DWORD dwMode; + DWORD dwStatus; + HANDLE hEventHook = NULL; + HMODULE hm_kernel32 = NULL, hm_user32 = NULL; + + if ((hm_kernel32 = LoadLibraryW(L"kernel32.dll")) == NULL || + (hm_user32 = LoadLibraryW(L"user32.dll")) == NULL || + (__SetCurrentConsoleFontEx = (__t_SetCurrentConsoleFontEx)GetProcAddress(hm_kernel32, "SetCurrentConsoleFontEx")) == NULL || + (__UnhookWinEvent = (__t_UnhookWinEvent)GetProcAddress(hm_user32, "UnhookWinEvent")) == NULL || + (__SetWinEventHook = (__t_SetWinEventHook)GetProcAddress(hm_user32, "SetWinEventHook")) == NULL) { + printf("cannot support a pseudo terminal. \n"); + return -1; + } + + pipe_in = GetStdHandle(STD_INPUT_HANDLE); + pipe_out = GetStdHandle(STD_OUTPUT_HANDLE); + pipe_err = GetStdHandle(STD_ERROR_HANDLE); + + /* copy pipe handles passed through std io*/ + if ((pipe_in == INVALID_HANDLE_VALUE) + || (pipe_out == INVALID_HANDLE_VALUE) + || (pipe_err == INVALID_HANDLE_VALUE)) + return -1; + + cp = GetConsoleCP(); + + /* Windows PTY sends cursor positions in absolute coordinates starting from <0,0> + * We send a clear screen upfront to simplify client */ + SendClearScreen(pipe_out); + + ZeroMemory(&inputSi, sizeof(STARTUPINFO)); + GetStartupInfo(&inputSi); + + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); + sa.bInheritHandle = TRUE; + + /* WM_APPEXIT */ + hostThreadId = GetCurrentThreadId(); + hostProcessId = GetCurrentProcessId(); + + InitializeCriticalSection(&criticalSection); + + hEventHook = __SetWinEventHook(EVENT_CONSOLE_CARET, EVENT_CONSOLE_LAYOUT, NULL, + ConsoleEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); + + memset(&si, 0, sizeof(STARTUPINFO)); + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + + // Copy our parent buffer sizes + si.cb = sizeof(STARTUPINFO); + si.dwFlags = 0; + + /* disable inheritance on pipe_in*/ + GOTO_CLEANUP_ON_FALSE(SetHandleInformation(pipe_in, HANDLE_FLAG_INHERIT, 0)); + + /*TODO - pick this up from system32*/ + cmd[0] = L'\0'; + if (ac) + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L"cmd.exe")); + + ac--; + av++; + if (ac) + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" /c")); + while (ac) { + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, *av)); + ac--; + av++; + } + + SetConsoleCtrlHandler(NULL, FALSE); + GOTO_CLEANUP_ON_FALSE(CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, + NULL, NULL, &si, &pi)); + childProcessId = pi.dwProcessId; + + FreeConsole(); + Sleep(20); + while (!AttachConsole(pi.dwProcessId)) + { + DWORD exit_code; + if (GetExitCodeProcess(pi.hProcess, &exit_code) && exit_code != STILL_ACTIVE) + break; + Sleep(100); + } + + /* monitor child exist */ + child = pi.hProcess; + monitor_thread = CreateThread(NULL, 0, MonitorChild, NULL, 0, NULL); + if (monitor_thread == INVALID_HANDLE_VALUE) + goto cleanup; + + /* disable Ctrl+C hander in this process*/ + SetConsoleCtrlHandler(NULL, TRUE); + + io_thread = CreateThread(NULL, 0, ProcessPipes, NULL, 0, NULL); + if (io_thread == INVALID_HANDLE_VALUE) + goto cleanup; + + ux_thread = CreateThread(NULL, 0, ProcessEventQueue, NULL, 0, NULL); + if (ux_thread == INVALID_HANDLE_VALUE) + goto cleanup; + + ProcessMessages(NULL); + +cleanup: + dwStatus = GetLastError(); + + DeleteCriticalSection(&criticalSection); + + if (child != INVALID_HANDLE_VALUE) + TerminateProcess(child, 0); + if (monitor_thread != INVALID_HANDLE_VALUE) + WaitForSingleObject(monitor_thread, INFINITE); + if (ux_thread != INVALID_HANDLE_VALUE) + TerminateThread(ux_thread, S_OK); + if (hEventHook) + __UnhookWinEvent(hEventHook); + + FreeConsole(); + + return 0; +} + +HANDLE child_pipe_read; +HANDLE child_pipe_write; +DWORD WINAPI MonitorChild_nopty( + _In_ LPVOID lpParameter + ) { + WaitForSingleObject(child, INFINITE); + CloseHandle(pipe_in); + //printf("XXXX CHILD PROCESS DEAD XXXXX"); + return 0; +} + +int start_withno_pty(int ac, wchar_t **av) { + STARTUPINFO si; + PROCESS_INFORMATION pi; + wchar_t cmd[MAX_CMD_LEN]; + SECURITY_ATTRIBUTES sa; + BOOL ret; + + pipe_in = GetStdHandle(STD_INPUT_HANDLE); + pipe_out = GetStdHandle(STD_OUTPUT_HANDLE); + pipe_err = GetStdHandle(STD_ERROR_HANDLE); + + /* copy pipe handles passed through std io*/ + if ((pipe_in == INVALID_HANDLE_VALUE) + || (pipe_out == INVALID_HANDLE_VALUE) + || (pipe_err == INVALID_HANDLE_VALUE)) + return -1; + + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); + sa.bInheritHandle = TRUE; + if (!CreatePipe(&child_pipe_read, &child_pipe_write, &sa, 128)) + return -1; + + memset(&si, 0, sizeof(STARTUPINFO)); + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = child_pipe_read; + si.hStdOutput = pipe_out; + si.hStdError = pipe_err; + + /* disable inheritance on child_pipe_write and pipe_in*/ + GOTO_CLEANUP_ON_FALSE(SetHandleInformation(pipe_in, HANDLE_FLAG_INHERIT, 0)); + GOTO_CLEANUP_ON_FALSE(SetHandleInformation(child_pipe_write, HANDLE_FLAG_INHERIT, 0)); + + /*TODO - pick this up from system32*/ + cmd[0] = L'\0'; + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L"cmd.exe")); + ac -= 2; + av += 2; + if (ac) + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" /c")); + while (ac) { + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_PATH, *av)); + ac--; + av++; + } + + GOTO_CLEANUP_ON_FALSE(CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)); + + /* close unwanted handles*/ + CloseHandle(child_pipe_read); + child_pipe_read = INVALID_HANDLE_VALUE; + + child = pi.hProcess; + /* monitor child exist */ + monitor_thread = CreateThread(NULL, 0, MonitorChild_nopty, NULL, 0, NULL); + if (monitor_thread == INVALID_HANDLE_VALUE) + goto cleanup; + + /* disable Ctrl+C hander in this process*/ + SetConsoleCtrlHandler(NULL, TRUE); + + /* process data from pipe_in and route appropriately */ + while (1) { + char buf[128]; + DWORD rd = 0, wr = 0, i = 0; + GOTO_CLEANUP_ON_FALSE(ReadFile(pipe_in, buf, 128, &rd, NULL)); + + while (i < rd) { + + /* skip arrow keys */ + if ((rd - i >= 3) && (buf[i] == '\033') && (buf[i + 1] == '[') + && (buf[i + 2] >= 'A') && (buf[i + 2] <= 'D')) { + i += 3; + continue; + } + + /* skip tab */ + if (buf[i] == '\t') { + i++; + continue; + } + + // Ctrl +C + if (buf[i] == '\003') { + GOTO_CLEANUP_ON_FALSE(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)); + in_cmd_len = 0; + i++; + continue; + } + + // for backspace, we need to send space and another backspace for visual erase + if (buf[i] == '\b') { + if (in_cmd_len > 0) { + GOTO_CLEANUP_ON_FALSE(WriteFile(pipe_out, "\b \b", 3, &wr, NULL)); + in_cmd_len--; + } + i++; + continue; + } + + //for CR and LF + if ((buf[i] == '\r') || (buf[i] == '\n')) { + + /* TODO - do a much accurate mapping */ + GOTO_CLEANUP_ON_FALSE(WriteFile(pipe_out, buf + i, 1, &wr, NULL)); + if ((buf[i] == '\r') && ((i == rd - 1) || (buf[i + 1] != '\n'))) { + buf[i] = '\n'; + GOTO_CLEANUP_ON_FALSE(WriteFile(pipe_out, buf + i, 1, &wr, NULL)); + } + in_cmd[in_cmd_len] = buf[i]; + in_cmd_len++; + GOTO_CLEANUP_ON_FALSE(WriteFile(child_pipe_write, in_cmd, in_cmd_len, &wr, NULL)); + in_cmd_len = 0; + i++; + continue; + } + + + GOTO_CLEANUP_ON_FALSE(WriteFile(pipe_out, buf + i, 1, &wr, NULL)); + in_cmd[in_cmd_len] = buf[i]; + in_cmd_len++; + if (in_cmd_len == MAX_CMD_LEN - 1) { + GOTO_CLEANUP_ON_FALSE(WriteFile(child_pipe_write, in_cmd, in_cmd_len, &wr, NULL)); + in_cmd_len = 0; + } + + i++; + } + } + +cleanup: + + if (child != INVALID_HANDLE_VALUE) + TerminateProcess(child, 0); + if (monitor_thread != INVALID_HANDLE_VALUE) + WaitForSingleObject(monitor_thread, INFINITE); + return 0; +} + +int wmain(int ac, wchar_t **av) { + + + /* create job to hold all child processes */ + { + /* TODO - this does not work as expected*/ + HANDLE job = CreateJobObject(NULL, NULL); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info; + memset(&job_info, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info))) + return -1; + CloseHandle(job); + } + + if ((ac == 1) || wcscmp(av[1], L"-nopty")) + return start_with_pty(ac, av); + else + return start_withno_pty(ac, av); +} \ No newline at end of file diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c new file mode 100644 index 000000000..8a74da9a3 --- /dev/null +++ b/contrib/win32/win32compat/signal.c @@ -0,0 +1,310 @@ +/* +* Author: Manoj Ampalam +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 "w32fd.h" +#include +#include +#include "signal_internal.h" + +/* pending signals to be processed */ +sigset_t pending_signals; + +/* signal handler table*/ +sighandler_t sig_handlers[W32_SIGMAX]; + +static VOID CALLBACK +sigint_APCProc( + _In_ ULONG_PTR dwParam + ) { + debug3("SIGINT APCProc()"); + sigaddset(&pending_signals, W32_SIGINT); +} + +static VOID CALLBACK +sigterm_APCProc( + _In_ ULONG_PTR dwParam + ) { + debug3("SIGTERM APCProc()"); + sigaddset(&pending_signals, W32_SIGTERM); +} + +static VOID CALLBACK +sigtstp_APCProc( + _In_ ULONG_PTR dwParam + ) { + debug3("SIGTSTP APCProc()"); + sigaddset(&pending_signals, W32_SIGTSTP); +} + +BOOL WINAPI +native_sig_handler(DWORD dwCtrlType) +{ + debug("Native Ctrl+C handler, CtrlType %d", dwCtrlType); + switch (dwCtrlType) { + case CTRL_C_EVENT: + QueueUserAPC(sigint_APCProc, main_thread, (ULONG_PTR)NULL); + return TRUE; + case CTRL_BREAK_EVENT: + QueueUserAPC(sigtstp_APCProc, main_thread, (ULONG_PTR)NULL); + return TRUE; + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + QueueUserAPC(sigterm_APCProc, main_thread, (ULONG_PTR)NULL); + /* wait for main thread to terminate */ + WaitForSingleObject(main_thread, INFINITE); + return TRUE; + default: + return FALSE; + } +} + +static VOID CALLBACK +sigwinch_APCProc( + _In_ ULONG_PTR dwParam + ) { + debug3("SIGTERM APCProc()"); + sigaddset(&pending_signals, W32_SIGWINCH); +} + + +void +queue_terminal_window_change_event() { + QueueUserAPC(sigwinch_APCProc, main_thread, (ULONG_PTR)NULL); +} + +void +sw_init_signal_handler_table() { + int i; + + SetConsoleCtrlHandler(native_sig_handler, TRUE); + sigemptyset(&pending_signals); + /* this automatically sets all to SIG_DFL (0)*/ + memset(sig_handlers, 0, sizeof(sig_handlers)); +} + +extern struct _children children; + +sighandler_t +sw_signal(int signum, sighandler_t handler) { + sighandler_t prev; + + debug2("signal() sig:%d, handler:%p", signum, handler); + if (signum >= W32_SIGMAX) { + errno = EINVAL; + return W32_SIG_ERR; + } + + prev = sig_handlers[signum]; + sig_handlers[signum] = handler; + return prev; +} + +int +sw_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { + /* this is only used by sshd to block SIGCHLD while doing waitpid() */ + /* our implementation of waidpid() is never interrupted, so no need to implement this for now*/ + debug3("sigprocmask() how:%d"); + return 0; +} + + + +int +sw_raise(int sig) { + debug("raise sig:%d", sig); + if (sig == W32_SIGSEGV) + return raise(SIGSEGV); /* raise native exception handler*/ + + if (sig >= W32_SIGMAX) { + errno = EINVAL; + return -1; + } + + /* execute user specified disposition */ + if (sig_handlers[sig] > W32_SIG_IGN) { + sig_handlers[sig](sig); + return 0; + } + + /* if set to ignore, nothing to do */ + if (sig_handlers[sig] == W32_SIG_IGN) + return 0; + + /* execute any default handlers */ + switch (sig) { + case W32_SIGCHLD: + sw_cleanup_child_zombies(); + break; + default: /* exit process */ + exit(0); + } + + return 0; +} + +/* processes pending signals, return -1 and errno=EINTR if any are processed*/ +static int +sw_process_pending_signals() { + sigset_t pending_tmp = pending_signals; + BOOL sig_int = FALSE; /* has any signal actually interrupted */ + + debug3("process_signals()"); + int i, exp[] = { W32_SIGCHLD , W32_SIGINT , W32_SIGALRM, W32_SIGTERM, W32_SIGTSTP, W32_SIGWINCH }; + + /* check for expected signals*/ + for (i = 0; i < (sizeof(exp) / sizeof(exp[0])); i++) + sigdelset(&pending_tmp, exp[i]); + if (pending_tmp) { + /* unexpected signals queued up */ + debug("process_signals() - ERROR unexpected signals in queue: %d", pending_tmp); + errno = ENOTSUP; + DebugBreak(); + return -1; + } + + /* take pending_signals local to prevent recursion in wait_for_any* loop */ + pending_tmp = pending_signals; + pending_signals = 0; + for (i = 0; i < (sizeof(exp) / sizeof(exp[0])); i++) { + if (sigismember(&pending_tmp, exp[i])) { + if (sig_handlers[exp[i]] != W32_SIG_IGN) { + sw_raise(exp[i]); + /* dont error EINTR for SIG_ALRM, */ + /* sftp client is not expecting it */ + if (exp[i] != W32_SIGALRM) + sig_int = TRUE; + } + + sigdelset(&pending_tmp, exp[i]); + } + } + + + /* by now all pending signals should have been taken care of*/ + if (pending_tmp) + DebugBreak(); + + if (sig_int) { + debug("process_queued_signals: WARNING - A signal has interrupted and was processed"); + errno = EINTR; + return -1; + } + + return 0; +} + +/* + * Main wait routine used by all blocking calls. + * It wakes up on + * - any signals (errno = EINTR ) + * - any of the supplied events set + * - any APCs caused by IO completions + * - time out + * - Returns 0 on IO completion and timeout, -1 on rest + * if milli_seconds is 0, this function returns 0, its called with 0 + * to execute any scheduled APCs +*/ +int +wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) +{ + HANDLE all_events[MAXIMUM_WAIT_OBJECTS]; + DWORD num_all_events; + DWORD live_children = children.num_children - children.num_zombies; + + num_all_events = num_events + live_children; + + if (num_all_events > MAXIMUM_WAIT_OBJECTS) { + debug("wait() - ERROR max events reached"); + errno = ENOTSUP; + return -1; + } + + memcpy(all_events, children.handles, live_children * sizeof(HANDLE)); + memcpy(all_events + live_children, events, num_events * sizeof(HANDLE)); + + debug3("wait() on %d events and %d children", num_events, live_children); + /* TODO - implement signal catching and handling */ + if (num_all_events) { + DWORD ret = WaitForMultipleObjectsEx(num_all_events, all_events, FALSE, + milli_seconds, TRUE); + if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_all_events - 1)) { + //woken up by event signalled + /* is this due to a child process going down*/ + if (children.num_children && ((ret - WAIT_OBJECT_0) < children.num_children)) { + sigaddset(&pending_signals, W32_SIGCHLD); + sw_child_to_zombie(ret - WAIT_OBJECT_0); + } + } + else if (ret == WAIT_IO_COMPLETION) { + /* APC processed due to IO or signal*/ + } + else if (ret == WAIT_TIMEOUT) { + /* timed out */ + return 0; + } + /* some other error*/ + else { + errno = EOTHER; + debug("ERROR: unxpected wait end: %d", ret); + return -1; + } + } + else { + DWORD ret = SleepEx(milli_seconds, TRUE); + if (ret == WAIT_IO_COMPLETION) { + /* APC processed due to IO or signal*/ + } + else if (ret == 0) { + /* timed out */ + return 0; + } + else { //some other error + errno = EOTHER; + debug("ERROR: unxpected SleepEx error: %d", ret); + return -1; + } + } + + if (pending_signals) { + return sw_process_pending_signals(); + } + return 0; +} + + +int +sw_initialize() { + memset(&children, 0, sizeof(children)); + sw_init_signal_handler_table(); + if (sw_init_timer() != 0) + return -1; + return 0; +} diff --git a/contrib/win32/win32compat/signal_internal.h b/contrib/win32/win32compat/signal_internal.h new file mode 100644 index 000000000..826ca9574 --- /dev/null +++ b/contrib/win32/win32compat/signal_internal.h @@ -0,0 +1,34 @@ +#include +#include "inc\defs.h" + + +int sw_initialize(); +sighandler_t sw_signal(int signum, sighandler_t handler); +int sw_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +int sw_raise(int sig); +int sw_kill(int pid, int sig); + +/* child processes */ +#define MAX_CHILDREN 50 +struct _children { + HANDLE handles[MAX_CHILDREN]; + DWORD process_id[MAX_CHILDREN]; + /* total children */ + DWORD num_children; + /* #zombies */ + /* (num_chileren - zombies) are live children */ + DWORD num_zombies; +}; + +int sw_add_child(HANDLE child, DWORD pid); +int sw_remove_child_at_index(DWORD index); +int sw_child_to_zombie(DWORD index); +void sw_cleanup_child_zombies(); + +struct _timer_info { + HANDLE timer; + ULONGLONG ticks_at_start; /* 0 if timer is not live */ + __int64 run_time_sec; /* time in seconds, timer is set to go off from ticks_at_start */ +}; +int sw_init_timer(); +unsigned int sw_alarm(unsigned int seconds); \ No newline at end of file diff --git a/contrib/win32/win32compat/signal_sigalrm.c b/contrib/win32/win32compat/signal_sigalrm.c new file mode 100644 index 000000000..e068c48b4 --- /dev/null +++ b/contrib/win32/win32compat/signal_sigalrm.c @@ -0,0 +1,89 @@ +/* +* Author: Manoj Ampalam +* +* Copyright(c) 2015 Microsoft Corp. +* All rights reserved +* +* Helper routines to support SIGALRM +* +* 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 "signal_internal.h" + +struct _timer_info timer_info; +extern sigset_t pending_signals; + +static VOID CALLBACK +sigalrm_APC( + _In_opt_ LPVOID lpArgToCompletionRoutine, + _In_ DWORD dwTimerLowValue, + _In_ DWORD dwTimerHighValue + ) { + sigaddset(&pending_signals, W32_SIGALRM); +} + +unsigned int +sw_alarm(unsigned int sec) { + LARGE_INTEGER due; + ULONGLONG sec_passed; + int ret = 0; + + debug3("alarm() %d secs", sec); + errno = 0; + /* cancel any live timer if seconds is 0*/ + if (sec == 0) { + CancelWaitableTimer(timer_info.timer); + timer_info.ticks_at_start = 0; + timer_info.run_time_sec = 0; + return 0; + } + + due.QuadPart = -10000000LL; //1 sec in 100 nanosec intervals + due.QuadPart *= sec; + /* this call resets the timer if it is already active */ + if (!SetWaitableTimer(timer_info.timer, &due, 0, sigalrm_APC, NULL, FALSE)) { + debug("alram() - ERROR SetWaitableTimer() %d", GetLastError()); + return 0;; + } + + /* if timer was already ative, return when it was due */ + if (timer_info.ticks_at_start) { + sec_passed = (GetTickCount64() - timer_info.ticks_at_start) / 1000; + if (sec_passed < timer_info.run_time_sec) + ret = timer_info.run_time_sec - sec_passed; + } + timer_info.ticks_at_start = GetTickCount64(); + timer_info.run_time_sec = sec; + return ret; +} + +int +sw_init_timer() { + memset(&timer_info, 0, sizeof(timer_info)); + timer_info.timer = CreateWaitableTimer(NULL, TRUE, NULL); + if (timer_info.timer == NULL) { + errno = ENOMEM; + return -1; + } + return 0; +} \ No newline at end of file diff --git a/contrib/win32/win32compat/signal_sigchld.c b/contrib/win32/win32compat/signal_sigchld.c new file mode 100644 index 000000000..afd0242f4 --- /dev/null +++ b/contrib/win32/win32compat/signal_sigchld.c @@ -0,0 +1,233 @@ +/* +* Author: Manoj Ampalam +* +* Copyright(c) 2015 Microsoft Corp. +* All rights reserved +* +* Helper routines to support SIGCLD and related routines implementation +* +* 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 "signal_internal.h" + +struct _children children; + +int +sw_add_child(HANDLE child, DWORD pid) { + DWORD first_zombie_index; + + debug("Register child %p pid %d, %d zombies of %d", child, pid, + children.num_zombies, children.num_children); + if (children.num_children == MAX_CHILDREN) { + errno = ENOMEM; + return -1; + } + if (children.num_zombies) { + first_zombie_index = children.num_children - children.num_zombies; + children.handles[children.num_children] = children.handles[first_zombie_index]; + children.process_id[children.num_children] = children.process_id[first_zombie_index]; + + children.handles[first_zombie_index] = child; + children.process_id[first_zombie_index] = pid; + } + else { + children.handles[children.num_children] = child; + children.process_id[children.num_children] = pid; + } + + + children.num_children++; + return 0; +} + +int +sw_remove_child_at_index(DWORD index) { + DWORD last_non_zombie; + + debug("Unregister child at index %d, %d zombies of %d", index, + children.num_zombies, children.num_children); + + if ((index >= children.num_children) + || (children.num_children == 0)) { + errno = EINVAL; + return -1; + } + + CloseHandle(children.handles[index]); + if (children.num_zombies == 0) { + children.handles[index] = children.handles[children.num_children - 1]; + children.process_id[index] = children.process_id[children.num_children - 1]; + } + else { + /* if its a zombie */ + if (index >= (children.num_children - children.num_zombies)) { + children.handles[index] = children.handles[children.num_children - 1]; + children.process_id[index] = children.process_id[children.num_children - 1]; + children.num_zombies--; + } + else { + last_non_zombie = children.num_children - children.num_zombies - 1; + children.handles[index] = children.handles[last_non_zombie]; + children.process_id[index] = children.process_id[last_non_zombie]; + + children.handles[last_non_zombie] = children.handles[children.num_children - 1]; + children.process_id[last_non_zombie] = children.process_id[children.num_children - 1]; + } + } + + children.num_children--; + return 0; +} + +int +sw_child_to_zombie(DWORD index) { + DWORD last_non_zombie, last_child, zombie_pid; + HANDLE zombie_handle; + + debug("zombie'ing child at index %d, %d zombies of %d", index, + children.num_zombies, children.num_children); + + if (index >= children.num_children) { + errno = EINVAL; + return -1; + } + + zombie_pid = children.process_id[index]; + zombie_handle = children.handles[index]; + last_non_zombie = children.num_children - children.num_zombies - 1; + last_child = children.num_children - 1; + + children.handles[index] = children.handles[last_non_zombie]; + children.process_id[index] = children.process_id[last_non_zombie]; + + children.handles[last_non_zombie] = children.handles[index]; + children.process_id[last_non_zombie] = children.process_id[index]; + + children.num_zombies++; + return 0; +} + +int +sw_kill(int pid, int sig) { + int child_index, i; + if (pid == GetCurrentProcessId()) + return sw_raise(sig); + + /* for child processes - only SIGTERM supported*/ + child_index = -1; + for (i = 0; i < children.num_children; i++) + if (children.process_id[i] == pid) { + child_index = i; + break; + } + + if (child_index != -1) + TerminateProcess(children.handles[child_index], 0); + return 0; +} + + +int waitpid(int pid, int *status, int options) { + DWORD index, ret, ret_id, exit_code, timeout = 0; + HANDLE process = NULL; + + debug3("waitpid - pid:%d, options:%d", pid, options); + if (options & (~WNOHANG)) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + + if ((pid < -1) || (pid == 0)) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + + if (children.num_children == 0) { + errno = ECHILD; + return -1; + } + + if (pid > 0) { + if (options != 0) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + /* find entry in table */ + for (index = 0; index < children.num_children; index++) + if (children.process_id[index] == pid) + break; + + if (index == children.num_children) { + errno = ECHILD; + return -1; + } + + process = children.handles[index]; + ret = WaitForSingleObject(process, INFINITE); + if (ret != WAIT_OBJECT_0) + DebugBreak();//fatal + + ret_id = children.process_id[index]; + GetExitCodeProcess(process, &exit_code); + /* process handle will be closed when its removed from list */ + sw_remove_child_at_index(index); + if (status) + *status = exit_code; + return ret_id; + } + + /* pid = -1*/ + timeout = INFINITE; + if (options & WNOHANG) + timeout = 0; + ret = WaitForMultipleObjects(children.num_children, children.handles, FALSE, timeout); + if ((ret >= WAIT_OBJECT_0) && (ret < (WAIT_OBJECT_0 + children.num_children))) { + index = ret - WAIT_OBJECT_0; + process = children.handles[index]; + ret_id = children.process_id[index]; + GetExitCodeProcess(process, &exit_code); + /* process handle will be closed when its removed from list */ + sw_remove_child_at_index(index); + if (status) + *status = exit_code; + return ret_id; + } + else if (ret == WAIT_TIMEOUT) { + /* TODO - assert that WNOHANG was specified*/ + return 0; + } + + DebugBreak();//fatal + return -1; +} + +void +sw_cleanup_child_zombies() { + int pid = 1; + while (pid > 0) { + pid = waitpid(-1, NULL, WNOHANG); + } +} \ No newline at end of file diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c new file mode 100644 index 000000000..8e5bbc234 --- /dev/null +++ b/contrib/win32/win32compat/socketio.c @@ -0,0 +1,1082 @@ +/* +* Author: Manoj Ampalam +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 "w32fd.h" +#include +#include "inc\utf.h" + +#define INTERNAL_SEND_BUFFER_SIZE 70*1024 //70KB + +#define INTERNAL_RECV_BUFFER_SIZE 70*1024 //70KB + +#define errno_from_WSALastError() errno_from_WSAError(WSAGetLastError()) + +/* maps WSAError to errno */ +static +int errno_from_WSAError(int wsaerrno) +{ + switch (wsaerrno) { + case WSAEWOULDBLOCK: + return EAGAIN; + case WSAEFAULT: + return EFAULT; + case WSAEINVAL: + return EINVAL; + case WSAECONNABORTED: + return ECONNABORTED; + case WSAECONNREFUSED: + return ECONNREFUSED; + case WSAEINPROGRESS: + return EINPROGRESS; + case WSAESHUTDOWN: + return ECONNRESET; + case WSAENOTCONN: + return ENOTCONN; + default: + /* */ + return wsaerrno - 10000; + } +} + +/* called before any other calls to socketio_ functions */ +int +socketio_initialize() { + WSADATA wsaData = { 0 }; + return WSAStartup(MAKEWORD(2, 2), &wsaData); +} + +/* cleanup */ +int +socketio_done() { + WSACleanup(); + return 0; +} + +/* state info that needs to be persisted for an inprocess acceptEx call*/ +struct acceptEx_context { + char lpOutputBuf[1024]; + SOCKET accept_socket; + LPFN_ACCEPTEX lpfnAcceptEx; + LPFN_GETACCEPTEXSOCKADDRS lpfnGuidGetAcceptExSockaddrs; + DWORD bytes_received; +}; + +/* initiate async acceptEx*/ +/* TODO - always return 0, set error in context, accept() will pick it up*/ +int +socketio_acceptEx(struct w32_io* pio) { + struct acceptEx_context *context; + + debug3("acceptEx - io:%p", pio); + context = (struct acceptEx_context *)pio->internal.context; + + ResetEvent(pio->read_overlapped.hEvent); + + /* create accepting socket */ + context->accept_socket = socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); + if (context->accept_socket == INVALID_SOCKET) { + errno = errno_from_WSALastError(); + debug("acceptEx - socket() ERROR:%d, io:%p", errno, pio); + return -1; + } + + if (TRUE == context->lpfnAcceptEx(pio->sock, + context->accept_socket, + context->lpOutputBuf, + 0, + sizeof(SOCKADDR_STORAGE) + 16, + sizeof(SOCKADDR_STORAGE) + 16, + &context->bytes_received, + &pio->read_overlapped)) + { + /* we are already connected. Set event so subsequent select will catch */ + SetEvent(pio->read_overlapped.hEvent); + } + else { + /* if overlapped io is in progress, we are good */ + if (WSAGetLastError() != ERROR_IO_PENDING) { + errno = errno_from_WSALastError(); + debug("acceptEx - AcceptEx() ERROR:%d, io:%p", errno, pio); + return -1; + } + } + + pio->read_details.pending = TRUE; + return 0; +} + +void +CALLBACK WSARecvCompletionRoutine( + IN DWORD dwError, + IN DWORD cbTransferred, + IN LPWSAOVERLAPPED lpOverlapped, + IN DWORD dwFlags + ) +{ + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); + debug2("WSARecvCompletionCB - io:%p, pending_state:%d, flags:%d, error:%d, received:%d", + pio, pio->read_details.pending, dwFlags, dwError, cbTransferred); + if (!dwError && !cbTransferred) + dwError = ERROR_GRACEFUL_DISCONNECT; + pio->read_details.error = dwError; + pio->read_details.remaining = cbTransferred; + pio->read_details.completed = 0; + pio->read_details.pending = FALSE; +} + +/* initiates async receive operation*/ +/* TODO - always return 0, or make this a void func. any error should be put in context*/ +int +socketio_WSARecv(struct w32_io* pio, BOOL* completed) { + int ret = 0; + WSABUF wsabuf; + DWORD recv_flags = 0; + + debug3("WSARecv - pio: %p", pio); + if (completed) + *completed = FALSE; + + /* initialize recv buffers if needed */ + wsabuf.len = INTERNAL_RECV_BUFFER_SIZE; + if (pio->read_details.buf == NULL) + { + wsabuf.buf = malloc(wsabuf.len); + + if (!wsabuf.buf) + { + errno = ENOMEM; + debug("WSARecv - ERROR:%d, io:%p", errno, pio); + return -1; + } + + pio->read_details.buf = wsabuf.buf; + pio->read_details.buf_size = wsabuf.len; + } + else + wsabuf.buf = pio->read_details.buf; + + + ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, + &WSARecvCompletionRoutine); + if (ret == 0) + { + pio->read_details.pending = TRUE; + /* receive has completed but APC is pending to be scheduled */ + debug2("WSARecv - WSARecv() returned 0, io:%p", pio); + if (completed) + *completed = TRUE; + } + else { /* (ret == SOCKET_ERROR) */ + if (WSAGetLastError() == WSA_IO_PENDING) + { + /* io is initiated and pending */ + debug2("WSARecv - reported IO pending"); + pio->read_details.pending = TRUE; + } + else { + errno = errno_from_WSALastError(); + debug("WSARecv - WSARecv() ERROR: io:%p %d", pio, errno); + return -1; + } + } + + return 0; +} + +/* implements socket() */ +struct w32_io* +socketio_socket(int domain, int type, int protocol) { + struct w32_io *pio = (struct w32_io*)malloc(sizeof(struct w32_io)); + if (!pio) { + errno = ENOMEM; + debug("socket - ERROR:%d, io:%p", errno, pio); + return NULL; + } + + memset(pio, 0, sizeof(struct w32_io)); + pio->sock = socket(domain, type, protocol); + if (pio->sock == INVALID_SOCKET) { + errno = errno_from_WSALastError(); + free(pio); + debug("socket - socket() ERROR:%d, io:%p", errno, pio); + return NULL; + } + + pio->internal.state = SOCK_INITIALIZED; + return pio; +} + +#define SET_ERRNO_ON_ERROR(expr) do { \ + int ret = (expr); \ + if (ret == SOCKET_ERROR) { \ + errno = errno_from_WSALastError(); \ + debug("%s - ERROR:%d", __FUNCTION__, errno); \ + } \ + return ret; \ +} while (0) + +/* implements setsockopt() */ +int +socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optval, + int optlen) { + if ((optname == SO_KEEPALIVE) || (optname == SO_REUSEADDR) || + (optname == TCP_NODELAY) || (optname == IPV6_V6ONLY)) + SET_ERRNO_ON_ERROR(setsockopt(pio->sock, level, optname, optval, optlen)); + else { + debug("setsockop - ERROR: unsupported optname:%d io:%p", optname, pio); + errno = ENOTSUP; + return -1; + } +} + +/* implements getsockopt() */ +int +socketio_getsockopt(struct w32_io* pio, int level, int optname, char* optval, int* optlen) { + SET_ERRNO_ON_ERROR(getsockopt(pio->sock, level, optname, optval, optlen)); +} + +/* implements getsockname() */ +int +socketio_getsockname(struct w32_io* pio, struct sockaddr* name, int* namelen) { + SET_ERRNO_ON_ERROR(getsockname(pio->sock, name, namelen)); +} + +/* implements getpeername */ +int +socketio_getpeername(struct w32_io* pio, struct sockaddr* name, int* namelen) { + SET_ERRNO_ON_ERROR(getpeername(pio->sock, name, namelen)); +} + +/* implements listen() */ +int +socketio_listen(struct w32_io* pio, int backlog) { + struct acceptEx_context* context; + + if (SOCKET_ERROR == listen(pio->sock, backlog)) { + errno = errno_from_WSALastError(); + debug("listen - listen() ERROR:%d io:%p", errno, pio); + return -1; + } + + /* prep for accept*/ + { + GUID GuidAcceptEx = WSAID_ACCEPTEX; + GUID GuidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; + DWORD dwBytes; + + context = (struct acceptEx_context*)malloc(sizeof(struct acceptEx_context)); + if (context == NULL) { + errno = ENOMEM; + debug("listen - ERROR:%d, io:%p", errno, pio); + return -1; + } + memset(context, 0, sizeof(struct acceptEx_context)); + if (SOCKET_ERROR == WSAIoctl(pio->sock, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidAcceptEx, sizeof(GuidAcceptEx), + &context->lpfnAcceptEx, sizeof(context->lpfnAcceptEx), + &dwBytes, NULL, NULL)) + { + free(context); + errno = errno_from_WSALastError(); + debug("listen - Ioctl1 ERROR:%d, io:%p", errno, pio); + return -1; + } + + if (SOCKET_ERROR == WSAIoctl(pio->sock, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidGetAcceptExSockaddrs, sizeof(GuidGetAcceptExSockaddrs), + &context->lpfnGuidGetAcceptExSockaddrs, sizeof(context->lpfnGuidGetAcceptExSockaddrs), + &dwBytes, NULL, NULL)) + { + free(context); + errno = errno_from_WSALastError(); + debug("listen - Ioctl2 ERROR:%d, io:%p", errno, pio); + return -1; + } + + pio->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if ((pio->read_overlapped.hEvent) == NULL) { + free(context); + errno = ENOMEM; + debug("listen - CreateEvent() ERROR:%d, io:%p", errno, pio); + return -1; + } + + context->accept_socket = INVALID_SOCKET; + pio->internal.context = context; + } + + pio->internal.state = SOCK_LISTENING; + return 0; +} + +/* implements bind() */ +int +socketio_bind(struct w32_io* pio, const struct sockaddr *name, int namelen) { + SET_ERRNO_ON_ERROR(bind(pio->sock, name, namelen)); +} + +/* implements recv() */ +int +socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { + BOOL completed = FALSE; + + debug3("recv - io:%p", pio); + + if ((buf == NULL) || (len == 0)) { + errno = EINVAL; + debug("recv - ERROR: invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); + return -1; + } + + if (flags != 0) { + errno = ENOTSUP; + debug("recv - ERROR: flags are not currently supported, io:%p", pio); + return -1; + } + + /* TODO - ensure socket is in accepted or connected state */ + + /* /io is initiated and pending */ + if (pio->read_details.pending) { + /* if recv is now in blocking mode, wait for data to be available */ + if (w32_io_is_blocking(pio)) { + debug2("recv - io is pending, call is blocking, io:%p", pio); + while (socketio_is_io_available(pio, TRUE) == FALSE) { + if (0 != wait_for_any_event(NULL, 0, INFINITE)) + return -1; + } + } + else { + errno = EAGAIN; + debug2("recv - io is already pending, io:%p", pio); + return -1; + } + } + + /* if we have some buffer copy it and return #bytes copied */ + if (pio->read_details.remaining) + { + int num_bytes_copied = min((int)len, pio->read_details.remaining); + memcpy(buf, pio->read_details.buf + pio->read_details.completed, + num_bytes_copied); + pio->read_details.remaining -= num_bytes_copied; + pio->read_details.completed += num_bytes_copied; + debug2("recv - returning %d bytes from prior completed IO, remaining:%d, io:%p", + num_bytes_copied, pio->read_details.remaining, pio); + return num_bytes_copied; + } + + + /* if there was an error on async call, return */ + if (pio->read_details.error) { + if (pio->read_details.error == ERROR_GRACEFUL_DISCONNECT) { + debug2("recv - connection closed, io:%p", pio); + /* connection is closed */ + return 0; + } + else { + errno = errno_from_WSAError(pio->read_details.error); + debug("recv - from CB ERROR:%d, io:%p", pio->read_details.error, pio); + pio->read_details.error = 0; + return -1; + } + } + + if (0 != socketio_WSARecv(pio, &completed)) + return -1; + + if (completed) { + /* Let APC be scheduled */ + debug2("recv - Letting APC to execute, io:%p", pio); + SleepEx(0, TRUE); + if (pio->read_details.pending) { + /* this shouldn't be happening */ + errno = EOTHER; + debug("recv - ERROR: Unexpected IO state, io:%p", pio); + return -1; + } + } + + if (w32_io_is_blocking(pio)) + { + /* wait until io is done */ + debug3("recv - socket in blocking mode, io:%p", pio); + while (socketio_is_io_available(pio, TRUE) == FALSE) { + if (0 != wait_for_any_event(NULL, 0, INFINITE)) + return -1; + } + } + else { + if (socketio_is_io_available(pio, TRUE) == FALSE) { + errno = EAGAIN; + debug2("recv - IO is pending, io:%p", pio); + return -1; + } + } + + /* + * by this time we should have some bytes in internal buffer + * or an error from callback + */ + if (pio->read_details.error) + { + if (pio->read_details.error == ERROR_GRACEFUL_DISCONNECT) { + /* connection is closed */ + debug2("recv - connection closed(2), io:%p", pio); + return 0; + } + else { + errno = errno_from_WSAError(pio->read_details.error); + pio->read_details.error = 0; + debug("recv - from CB(2) ERROR:%d, io:%p", errno, pio); + return -1; + } + } + + if (pio->read_details.remaining) { + int num_bytes_copied = min((int)len, pio->read_details.remaining); + memcpy(buf, pio->read_details.buf, num_bytes_copied); + pio->read_details.remaining -= num_bytes_copied; + pio->read_details.completed = num_bytes_copied; + debug2("recv - (2) returning %d bytes from completed IO, remaining:%d, io:%p", + num_bytes_copied, pio->read_details.remaining, pio); + return num_bytes_copied; + } + else { + /* this should not happen */ + errno = EOTHER; + debug("recv - (2) ERROR:Unexpected IO state, io:%p", pio); + return -1; + } + +} + +void +CALLBACK WSASendCompletionRoutine( + IN DWORD dwError, + IN DWORD cbTransferred, + IN LPWSAOVERLAPPED lpOverlapped, + IN DWORD dwFlags + ) +{ + struct w32_io* pio = + (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); + debug2("WSASendCB - io:%p, pending_state:%d, error:%d, sent:%d of remaining:%d", + pio, pio->write_details.pending, dwError, cbTransferred, + pio->write_details.remaining); + pio->write_details.error = dwError; + /* TODO - assert that remaining == cbTransferred */ + if ((dwError == 0) && (pio->write_details.remaining != cbTransferred)) { + debug("WSASendCB - ERROR: broken assumption, io:%p, sent:%d, remaining:%d", pio, + cbTransferred, pio->write_details.remaining); + DebugBreak(); + } + pio->write_details.remaining -= cbTransferred; + pio->write_details.pending = FALSE; +} + +/* implementation of send() */ +int +socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { + int ret = 0; + WSABUF wsabuf; + + debug2("send - io:%p", pio); + + if ((buf == NULL) || (len == 0)) { + errno = EINVAL; + debug("send - ERROR invalid arguments, buf:%p, len:%d, io:%p", buf, len, pio); + return -1; + } + + if (flags != 0) { + errno = ENOTSUP; + debug("send - ERROR: flags are not currently supported, io:%p", pio); + return -1; + } + + /* TODO - ensure socket is in accepted or connected state */ + + /* if io is already pending */ + if (pio->write_details.pending) + { + if (w32_io_is_blocking(pio)) + { + debug2("send - io is pending, call is blocking, io:%p", pio); + while (pio->write_details.pending) { + if (wait_for_any_event(NULL, 0, INFINITE) == -1) + return -1; + } + } + else { + errno = EAGAIN; + debug2("send - IO currently pending, EAGAIN, io:%p", pio); + return -1; + } + } + + + if (pio->write_details.error) { + errno = errno_from_WSAError(pio->write_details.error); + debug("ERROR:%d, io:%p", errno, pio); + return -1; + } + + /* initialize buffers if needed */ + wsabuf.len = INTERNAL_SEND_BUFFER_SIZE; + if (pio->write_details.buf == NULL) + { + wsabuf.buf = malloc(wsabuf.len); + if (!wsabuf.buf) + { + errno = ENOMEM; + debug("send - ERROR:%d, io:%p", errno, pio); + return -1; + } + + pio->write_details.buf = wsabuf.buf; + pio->write_details.buf_size = wsabuf.len; + } + else { + wsabuf.buf = pio->write_details.buf; + } + + wsabuf.len = min(wsabuf.len, (int)len); + memcpy(wsabuf.buf, buf, wsabuf.len); + + /* TODO - implement flags support if needed */ + ret = WSASend(pio->sock, &wsabuf, 1, NULL, 0, &pio->write_overlapped, + &WSASendCompletionRoutine); + + if (ret == 0) + { + /* send has completed and APC is scheduled, let it run */ + debug2("send - WSASend() returned 0, APC scheduled io:%p", pio); + pio->write_details.pending = TRUE; + pio->write_details.remaining = wsabuf.len; + SleepEx(0, TRUE); + if ((pio->write_details.pending) || (pio->write_details.remaining != 0)) { + errno = EOTHER; + debug("send - ERROR: Unexpected IO state, io:%p", pio); + return -1; + } + + /* return num of bytes written */ + return wsabuf.len; + } + else { + if (WSAGetLastError() == WSA_IO_PENDING) + { + /* io is initiated and pending */ + debug2("send - WSASend reported IO pending, io:%p", pio); + pio->write_details.pending = TRUE; + pio->write_details.remaining = wsabuf.len; + if (w32_io_is_blocking(pio)) + { + /* wait until io is done */ + debug3("send - waiting as socket is in blocking mode, io:%p", pio); + while (pio->write_details.pending) + if (wait_for_any_event(NULL, 0, INFINITE) == -1) { + /* if interrupted but send has completed, we are good*/ + if ((errno != EINTR) || (pio->write_details.pending)) + return -1; + errno = 0; + } + } + + debug3("send - returning %d, io:%p", wsabuf.len, pio); + return wsabuf.len; + } + else { + errno = errno_from_WSALastError(); + debug("send - WSASend() ERROR:%d, io:%p", errno, pio); + return -1; + } + } +} + +/* shutdown() implementation */ +int +socketio_shutdown(struct w32_io* pio, int how) { + SET_ERRNO_ON_ERROR(shutdown(pio->sock, how)); +} + +/* socket close() implementation */ +int +socketio_close(struct w32_io* pio) { + debug2("close - io:%p", pio); + closesocket(pio->sock); + /* wait for pending io to abort */ + SleepEx(0, TRUE); + if ( ((pio->internal.state == SOCK_CONNECTED) || (pio->internal.state == SOCK_ACCEPTED)) + && (pio->read_details.pending || pio->write_details.pending)) { + debug2("close - IO is still pending on closed socket. read:%d, write:%d, io:%p", + pio->read_details.pending, pio->write_details.pending, pio); + DebugBreak(); + } + if (pio->internal.state == SOCK_LISTENING) { + if (pio->read_overlapped.hEvent) + CloseHandle(pio->read_overlapped.hEvent); + if (pio->internal.context) + { + struct acceptEx_context *ctx = (struct acceptEx_context*)pio->internal.context; + if (ctx->accept_socket != INVALID_SOCKET) + closesocket(ctx->accept_socket); + free(pio->internal.context); + } + + } + else if (pio->internal.state == SOCK_CONNECTING) { + if (pio->write_overlapped.hEvent) + CloseHandle(pio->write_overlapped.hEvent); + } + else { + if (pio->read_details.buf) + free(pio->read_details.buf); + + if (pio->write_details.buf) + free(pio->write_details.buf); + } + + free(pio); + return 0; +} + +/* accept() implementation */ +struct w32_io* +socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { + struct w32_io *accept_io = NULL; + int iResult = 0; + struct acceptEx_context* context; + struct sockaddr *local_address,*remote_address; + int local_address_len, remote_address_len; + + debug3("accept - io:%p", pio); + /* start io if not already started */ + if (pio->read_details.pending == FALSE) { + if (socketio_acceptEx(pio) != 0) { + return NULL; + } + } + + if (w32_io_is_blocking(pio)) { + /* block until accept io is complete */ + while (FALSE == socketio_is_io_available(pio, TRUE)) + if (-1 == wait_for_any_event(&pio->read_overlapped.hEvent, + 1, INFINITE)) + return NULL; + } + else { + /* if i/o is not ready */ + if (FALSE == socketio_is_io_available(pio, TRUE)) { + errno = EAGAIN; + debug2("accept is pending, io:%p", pio); + return NULL; + } + + } + + context = (struct acceptEx_context*)pio->internal.context; + pio->read_details.pending = FALSE; + ResetEvent(pio->read_overlapped.hEvent); + + if (pio->read_details.error) { + errno = errno_from_WSAError(pio->read_details.error); + debug("accept - ERROR: async io completed with error: %d, io:%p", errno, pio); + goto on_error; + } + + if (0 != setsockopt(context->accept_socket, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, (char*)&pio->sock, sizeof(pio->sock))) { + errno = errno_from_WSALastError(); + debug("accept - ERROR: setsockopt failed:%d, io:%p", errno, pio); + goto on_error; + } + + accept_io = (struct w32_io*)malloc(sizeof(struct w32_io)); + if (!accept_io) { + errno = ENOMEM; + debug("accept - ERROR:%d, io:%p", errno, pio); + goto on_error; + } + memset(accept_io, 0, sizeof(struct w32_io)); + + accept_io->sock = context->accept_socket; + accept_io->internal.state = SOCK_ACCEPTED; + context->accept_socket = INVALID_SOCKET; + debug2("accept io:%p", accept_io); + + if ((addr != NULL) && (addrlen != NULL)) { + context->lpfnGuidGetAcceptExSockaddrs(context->lpOutputBuf, 0, + sizeof(SOCKADDR_STORAGE) + 16, + sizeof(SOCKADDR_STORAGE) + 16, &local_address, + &local_address_len, &remote_address, &remote_address_len); + if (remote_address_len) { + memcpy(addr, remote_address, remote_address_len); + *addrlen = remote_address_len; + } + } + return accept_io; + +on_error: + if (context->accept_socket != INVALID_SOCKET) { + closesocket(context->accept_socket); + context->accept_socket = INVALID_SOCKET; + } + + return NULL; +} + +/* initiates an async connect*/ +int +socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) { + + struct sockaddr_in tmp_addr4; + struct sockaddr_in6 tmp_addr6; + SOCKADDR* tmp_addr; + size_t tmp_addr_len; + DWORD tmp_bytes; + GUID connectex_guid = WSAID_CONNECTEX; + LPFN_CONNECTEX ConnectEx; + + debug3("connectex - io:%p", pio); + if (name->sa_family == AF_INET6) { + ZeroMemory(&tmp_addr6, sizeof(tmp_addr6)); + tmp_addr6.sin6_family = AF_INET6; + tmp_addr6.sin6_port = 0; + tmp_addr = (SOCKADDR*)&tmp_addr6; + tmp_addr_len = sizeof(tmp_addr6); + } + else if (name->sa_family == AF_INET) { + ZeroMemory(&tmp_addr4, sizeof(tmp_addr4)); + tmp_addr4.sin_family = AF_INET; + tmp_addr4.sin_port = 0; + tmp_addr = (SOCKADDR*)&tmp_addr4; + tmp_addr_len = sizeof(tmp_addr4); + } + else { + errno = ENOTSUP; + debug("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio); + return -1; + } + + if (SOCKET_ERROR == bind(pio->sock, tmp_addr, (int)tmp_addr_len)) + { + errno = errno_from_WSALastError(); + debug("connectex - ERROR: bind failed :%d, io:%p", WSAGetLastError(), pio); + return -1; + } + + if (SOCKET_ERROR == WSAIoctl(pio->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &connectex_guid, sizeof(connectex_guid), + &ConnectEx, sizeof(ConnectEx), + &tmp_bytes, NULL, NULL)) + { + errno = errno_from_WSALastError(); + debug("connectex - ioctl ERROR:%d, io:%p", WSAGetLastError(), pio); + return -1; + } + + if ((!pio->write_overlapped.hEvent) + && ((pio->write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)) { + errno = ENOMEM; + debug("connectex - ERROR CreateEvent failed:%d, io:%p", errno, pio); + return -1; + } + + ResetEvent(pio->write_overlapped.hEvent); + if (TRUE == ConnectEx(pio->sock, name, namelen, NULL, 0, NULL, + &pio->write_overlapped)) { + /* set completion event to indicates that async connect has completed */ + SetEvent(pio->write_overlapped.hEvent); + } + else { + if (WSAGetLastError() != ERROR_IO_PENDING) { + CloseHandle(pio->write_overlapped.hEvent); + pio->write_overlapped.hEvent = 0; + errno = errno_from_WSALastError(); + debug("connectex - ERROR ConnectEx() :%d, io:%p", errno, pio); + return -1; + } + } + + pio->write_details.pending = TRUE; + pio->internal.state = SOCK_CONNECTING; + return 0; +} + +/* connect implementation */ +int +socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) { + + debug3("connect - io:%p", pio); + if (pio->write_details.pending == FALSE) { + if (-1 == socketio_connectex(pio, name, namelen)) + return -1; + } + + if (w32_io_is_blocking(pio)) { + /* block until connect io is complete */ + while (FALSE == socketio_is_io_available(pio, TRUE)) { + if (-1 == wait_for_any_event(&pio->write_overlapped.hEvent, + 1, INFINITE)) + return -1; + } + } + else { + /* if i/o is not ready */ + if (FALSE == socketio_is_io_available(pio, TRUE)) { + errno = EINPROGRESS; + debug2("connect - in progress, io:%p", pio); + return -1; + } + + } + + return socketio_finish_connect(pio); +} + +int +socketio_finish_connect(struct w32_io* pio) { + + debug3("finish_connect, io:%p", pio); + + if (pio->write_details.error) { + errno = errno_from_WSAError(pio->write_details.error); + debug("finish_connect - ERROR: async io completed with error: %d, io:%p", errno, pio); + return -1; + } + + if (0 != setsockopt(pio->sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0)) { + errno = errno_from_WSALastError(); + debug("finish_connect - ERROR: setsockopt failed:%d, io:%p", errno, pio); + return -1; + } + + /* Reset any state used during connect */ + /* close event handle */ + CloseHandle(pio->write_overlapped.hEvent); + ZeroMemory(&pio->write_details, sizeof(pio->write_details)); + pio->internal.state = SOCK_CONNECTED; + return 0; +} + +/* checks if a given io is ready/available */ +BOOL +socketio_is_io_available(struct w32_io* pio, BOOL rd) { + + if ((pio->internal.state == SOCK_LISTENING) || + (pio->internal.state == SOCK_CONNECTING)) { + DWORD numBytes = 0; + DWORD flags; + BOOL sock_listening = (pio->internal.state == SOCK_LISTENING); + OVERLAPPED *overlapped = + sock_listening ? &pio->read_overlapped : &pio->write_overlapped; + BOOL pending = + sock_listening ? pio->read_details.pending : pio->write_details.pending; + + if (pending) + /* if there is an error to be picked up */ + if (sock_listening) { + if (pio->read_details.error) + return TRUE; + } + else { + if (pio->write_details.error) + return TRUE; + } + + if (WSAGetOverlappedResult(pio->sock, overlapped, + &numBytes, FALSE, &flags)) + return TRUE; + else if (WSAGetLastError() != WSA_IO_INCOMPLETE) { + if (sock_listening) + pio->read_details.error = WSAGetLastError(); + else + pio->write_details.error = WSAGetLastError(); + return TRUE; + } + + return FALSE; + } + else if (rd) { + if (pio->read_details.remaining || pio->read_details.error) + return TRUE; + else + return FALSE; + } + else { + return (pio->write_details.pending == FALSE) ? TRUE : FALSE; + } + +} +/*start async io (if needed) for accept and recv*/ +void +socketio_on_select(struct w32_io* pio, BOOL rd) { + + enum w32_io_sock_state sock_state = pio->internal.state; + + debug2("on_select - io:%p type:%d rd:%d", pio, pio->type, rd); + + //nothing to do for writes (that includes connect) + if (!rd) + return; + + //listening socket - acceptEx if needed + if (sock_state == SOCK_LISTENING) { + if (pio->read_details.pending == FALSE) + if (socketio_acceptEx(pio) != 0) { + /* set error, accept will pick it*/ + pio->read_details.error = errno; + errno = 0; + pio->read_details.pending = TRUE; + SetEvent(pio->read_overlapped.hEvent); + return; + } + } + else { + //connected socket - WSARecv if needed + if ((!pio->read_details.pending) && (!socketio_is_io_available(pio, rd))) + if (socketio_WSARecv(pio, NULL) != 0) { + /* set error, recv() will pick it */ + pio->read_details.error = errno; + errno = 0; + return; + } + } + +} + +int +w32_gethostname(char *name_utf8, size_t len) { + wchar_t name_utf16[256]; + char* tmp_name_utf8 = NULL; + + if (IsWindows8OrGreater()) { + /* TODO - GetHostNameW not present in Win7, do GetProcAddr on Win8+*/ + // if (GetHostNameW(name_utf16, 256) == SOCKET_ERROR) { + // errno = errno_from_WSALastError(); + // return -1; + // } + + // if ((tmp_name_utf8 = utf16_to_utf8(name_utf16)) == NULL || + // strlen(tmp_name_utf8) >= len) { + // errno = EFAULT; //?? + // return -1; + // } + + // memcpy(name_utf8, tmp_name_utf8, strlen(tmp_name_utf8) + 1); + // free(tmp_name_utf8); + // return 0; + return gethostname(name_utf8, len); + } + else + return gethostname(name_utf8, len); +} + +void +w32_freeaddrinfo(struct addrinfo *ai) { + struct addrinfo *cur; + while (ai) { + cur = ai; + ai = ai->ai_next; + if (cur->ai_addr) + free(cur->ai_addr); + if (cur->ai_canonname) + free(cur->ai_canonname); + free(cur); + } +} + +int +w32_getaddrinfo(const char *node_utf8, const char *service_utf8, + const struct addrinfo *hints, struct addrinfo **res) { + int ret = 0; + wchar_t *node_utf16 = NULL, *service_utf16 = NULL; + struct addrinfoW *info_w = NULL; + *res = NULL; + + if ((node_utf8 && (node_utf16 = utf8_to_utf16(node_utf8)) == NULL) || + (service_utf8 && (service_utf16 = utf8_to_utf16(service_utf8)) == NULL)) { + ret = EAI_MEMORY; + goto done; + } + + if ((ret = GetAddrInfoW(node_utf16, service_utf16, (ADDRINFOW*)hints, &info_w)) != 0) + goto done; + + /* copy info_w to res */ + { + struct addrinfoW **cur_w = &info_w; + struct addrinfo **cur = res; + + while (*cur_w) { + if ((*cur = malloc(sizeof(struct addrinfo))) == NULL) { + ret = EAI_MEMORY; + goto done; + } + memcpy(*cur, *cur_w, sizeof(struct addrinfo)); + (*cur)->ai_next = NULL; + if (((*cur_w)->ai_canonname && ((*cur)->ai_canonname = utf16_to_utf8((*cur_w)->ai_canonname)) == NULL) || + ((*cur_w)->ai_addrlen && ((*cur)->ai_addr = malloc((*cur_w)->ai_addrlen)) == NULL) ) { + ret = EAI_MEMORY; + goto done; + + } + if ((*cur_w)->ai_addrlen) + memcpy((*cur)->ai_addr, (*cur_w)->ai_addr, (*cur_w)->ai_addrlen); + cur_w = &(*cur_w)->ai_next; + cur = &(*cur)->ai_next; + } + } + +done: + if (node_utf16) + free(node_utf16); + if (service_utf16) + free(service_utf16); + if (info_w) + FreeAddrInfoW(info_w); + if (ret != 0 && *res) { + w32_freeaddrinfo(*res); + *res = NULL; + } + return ret; +} + + diff --git a/contrib/win32/win32compat/ssh-agent/agent-main.c b/contrib/win32/win32compat/ssh-agent/agent-main.c new file mode 100644 index 000000000..e7634bfa8 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/agent-main.c @@ -0,0 +1,159 @@ +/* + * Author: Manoj Ampalam + * ssh-agent implementation on Windows + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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 "agent.h" + + +int scm_start_service(DWORD, LPWSTR*); + +SERVICE_TABLE_ENTRYW dispatch_table[] = +{ + { L"ssh-agent", (LPSERVICE_MAIN_FUNCTIONW)scm_start_service }, + { NULL, NULL } +}; +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; + + +static VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) +{ + service_status.dwCurrentState = dwCurrentState; + service_status.dwWin32ExitCode = dwWin32ExitCode; + service_status.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + service_status.dwControlsAccepted = 0; + else + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) + service_status.dwCheckPoint = 0; + else + service_status.dwCheckPoint = 1; + + SetServiceStatus(service_status_handle, &service_status); +} + +static VOID WINAPI service_handler(DWORD dwControl) +{ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: { + ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 500); + agent_shutdown(); + ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); + return; + } + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } + + ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0); +} + +BOOL WINAPI ctrl_c_handler( + _In_ DWORD dwCtrlType +) { + /* for any Ctrl type, shutdown agent*/ + debug("Ctrl+C received"); + agent_shutdown(); + return TRUE; +} + +int wmain(int argc, wchar_t **argv) { + + w32posix_initialize(); + load_config(); + if (!StartServiceCtrlDispatcherW(dispatch_table)) { + if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { + + if (argc == 2) { + if (wcsncmp(argv[1], L"-ddd", 4) == 0) + log_init("ssh-agent", 7, 1, 1); + else if (wcsncmp(argv[1], L"-dd", 3) == 0) + log_init("ssh-agent", 6, 1, 1); + else if (wcsncmp(argv[1], L"-d", 2) == 0) + log_init("ssh-agent", 5, 1, 1); + + if (wcsncmp(argv[1], L"-d", 2) == 0) { + SetConsoleCtrlHandler(ctrl_c_handler, TRUE); + agent_start(TRUE, FALSE, 0); + return 0; + } + + /*agent process is likely a spawned child*/ + char* h = 0; + h += _wtoi(*(argv + 1)); + if (h != 0) { + log_init("ssh-agent", config_log_level(), 1, 0); + agent_start(FALSE, TRUE, h); + return 0; + } + } + /* to support linux compat scenarios where ssh-agent.exe is typically launched per session*/ + /* - just start ssh-agent service if needed */ + { + SC_HANDLE sc_handle, svc_handle; + DWORD err; + + if ((sc_handle = OpenSCManagerW(NULL, NULL, SERVICE_START)) == NULL || + (svc_handle = OpenServiceW(sc_handle, L"ssh-agent", SERVICE_START)) == NULL) { + fatal("unable to open service handle"); + return -1; + } + + if (StartService(svc_handle, 0, NULL) == FALSE && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) { + fatal("unable to start ssh-agent service, error :%d", GetLastError()); + return -1; + } + + return 0; + } + } + else + return -1; + } + return 0; +} + +int scm_start_service(DWORD num, LPWSTR* args) { + service_status_handle = RegisterServiceCtrlHandlerW(L"ssh-agent", service_handler); + ZeroMemory(&service_status, sizeof(service_status)); + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300); + ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); + log_init("ssh-agent", config_log_level(), 1, 0); + agent_start(FALSE, FALSE, 0); + return 0; +} + diff --git a/contrib/win32/win32compat/ssh-agent/agent-request.h b/contrib/win32/win32compat/ssh-agent/agent-request.h new file mode 100644 index 000000000..3d7c3df9f --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/agent-request.h @@ -0,0 +1,21 @@ +typedef unsigned char u_int8_t; +typedef unsigned short u_int16_t; +typedef unsigned int u_int32_t; +typedef unsigned __int64 u_int64_t; +#define __attribute__(a) +#include "rsa.h" +#include "sshbuf.h" +#include "sshkey.h" +#include "authfd.h" +#include "digest.h" + + +/* key management */ +int process_add_identity(struct sshbuf*, struct sshbuf*, struct agent_connection*); +int process_request_identities(struct sshbuf*, struct sshbuf*, struct agent_connection*); +int process_sign_request(struct sshbuf*, struct sshbuf*, struct agent_connection*); +int process_remove_key(struct sshbuf*, struct sshbuf*, struct agent_connection*); +int process_remove_all(struct sshbuf*, struct sshbuf*, struct agent_connection*); +int process_authagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*); + +/* auth */ diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c new file mode 100644 index 000000000..62e625d98 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -0,0 +1,266 @@ +/* + * Author: Manoj Ampalam + * ssh-agent implementation on Windows + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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 "agent.h" +#include +#include +#define BUFSIZE 5 * 1024 + +static HANDLE ioc_port = NULL; +static BOOL debug_mode = FALSE; + +#define AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent" + +static HANDLE event_stop_agent; +static OVERLAPPED ol; +static HANDLE pipe; +static SECURITY_ATTRIBUTES sa; + +static int +init_listener() { + { + if ((ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { + debug("cannot create event ERROR:%d", GetLastError()); + return GetLastError(); + } + pipe = INVALID_HANDLE_VALUE; + sa.bInheritHandle = FALSE; + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:P(A;; GA;;; AU)", SDDL_REVISION_1, + &sa.lpSecurityDescriptor, &sa.nLength)) { + debug("cannot convert sddl ERROR:%d", GetLastError()); + return GetLastError(); + } + } + + return 0; +} + +static void +agent_cleanup() { + { + if (ol.hEvent != NULL) + CloseHandle(ol.hEvent); + if (pipe != INVALID_HANDLE_VALUE) + CloseHandle(pipe); + } + if (ioc_port) + CloseHandle(ioc_port); + return; +} + +static DWORD WINAPI +iocp_work(LPVOID lpParam) { + DWORD bytes; + struct agent_connection* con = NULL; + OVERLAPPED *p_ol; + while (1) { + con = NULL; + p_ol = NULL; + if (GetQueuedCompletionStatus(ioc_port, &bytes, &(ULONG_PTR)con, &p_ol, INFINITE) == FALSE) { + debug("iocp error: %d on %p \n", GetLastError(), con); + if (con) + agent_connection_on_error(con, GetLastError()); + else + return 0; + } + else + agent_connection_on_io(con, bytes, p_ol); + + } +} + +static void +process_connection(HANDLE pipe) { + struct agent_connection* con; + + if ((con = malloc(sizeof(struct agent_connection))) == NULL) + fatal("failed to alloc"); + + memset(con, 0, sizeof(struct agent_connection)); + con->connection = pipe; + if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port) + fatal("failed to assign pipe to ioc_port"); + + agent_connection_on_io(con, 0, &con->ol); + iocp_work(NULL); +} + +static void +agent_listen_loop() { + DWORD r; + HANDLE wait_events[2]; + + wait_events[0] = event_stop_agent; + + wait_events[1] = ol.hEvent; + + while (1) { + { + { + pipe = CreateNamedPipeW( + AGENT_PIPE_ID, // pipe name + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access + PIPE_TYPE_BYTE | // message type pipe + PIPE_READMODE_BYTE | // message-read mode + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + BUFSIZE, // output buffer size + BUFSIZE, // input buffer size + 0, // client time-out + &sa); + + if (pipe == INVALID_HANDLE_VALUE) { + verbose("cannot create listener pipe ERROR:%d", GetLastError()); + SetEvent(event_stop_agent); + } + else if (ConnectNamedPipe(pipe, &ol) != FALSE) { + verbose("ConnectNamedPipe returned TRUE unexpectedly "); + SetEvent(event_stop_agent); + } + + if (GetLastError() == ERROR_PIPE_CONNECTED) { + debug("Client has already connected"); + SetEvent(ol.hEvent); + } + + if (GetLastError() != ERROR_IO_PENDING) { + debug("ConnectNamedPipe failed ERROR: %d", GetLastError()); + SetEvent(event_stop_agent); + } + + } + } + + r = WaitForMultipleObjects(2, wait_events, FALSE, INFINITE); + if (r == WAIT_OBJECT_0) { + //received signal to shutdown + debug("shutting down"); + agent_cleanup(); + return; + } + else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + 1))) { + /* process incoming connection */ + HANDLE con = pipe; + DWORD client_pid = 0; + pipe = INVALID_HANDLE_VALUE; + GetNamedPipeClientProcessId(con, &client_pid); + verbose("client pid %d connected", client_pid); + if (debug_mode) { + process_connection(con); + agent_cleanup(); + return; + } + else { + /* spawn a child to take care of this*/ + wchar_t path[MAX_PATH], module_path[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + si.cb = sizeof(STARTUPINFOW); + memset(&si, 0, sizeof(STARTUPINFOW)); + GetModuleFileNameW(NULL, module_path, MAX_PATH); + SetHandleInformation(con, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + if ((swprintf_s(path, MAX_PATH, L"%s %d", module_path, (int)(intptr_t)con) == -1 ) || + (CreateProcessW(NULL, path, NULL, NULL, TRUE, + DETACHED_PROCESS, NULL, NULL, + &si, &pi) == FALSE)) { + verbose("Failed to create child process %ls ERROR:%d", module_path, GetLastError()); + } + else { + debug("spawned worker %d for agent client pid %d ", pi.dwProcessId, client_pid); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + SetHandleInformation(con, HANDLE_FLAG_INHERIT, 0); + CloseHandle(con); + } + + } + else { + fatal("wait on events ended with %d ERROR:%d", r, GetLastError()); + } + + } +} + +void agent_cleanup_connection(struct agent_connection* con) { + debug("connection %p clean up", con); + CloseHandle(con->connection); + if (con->hProfile) + UnloadUserProfile(con->auth_token, con->hProfile); + if (con->auth_token) + CloseHandle(con->auth_token); + free(con); + CloseHandle(ioc_port); + ioc_port = NULL; +} + +void agent_shutdown() { + verbose("shutdown"); + SetEvent(event_stop_agent); +} + +#define REG_AGENT_SDDL L"D:P(A;; GR;;; AU)(A;; GA;;; SY)(A;; GA;;; BA)" + +void +agent_start(BOOL dbg_mode, BOOL child, HANDLE pipe) { + int r; + HKEY agent_root = NULL; + DWORD process_id = GetCurrentProcessId(); + + verbose("agent_start pid:%d, dbg:%d, child:%d, pipe:%d", process_id, dbg_mode, child, pipe); + debug_mode = dbg_mode; + + if ((ioc_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0)) == NULL) + fatal("cannot create ioc port ERROR:%d", GetLastError()); + + + if (child == FALSE) { + SECURITY_ATTRIBUTES sa; + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(sa); + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(REG_AGENT_SDDL, SDDL_REVISION_1, &sa.lpSecurityDescriptor, &sa.nLength)) + fatal("ConvertStringSecurityDescriptorToSecurityDescriptorW failed"); + if ((r = RegCreateKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_ROOT, 0, 0, 0, KEY_WRITE, &sa, &agent_root, 0)) != ERROR_SUCCESS) + fatal("cannot create agent root reg key, ERROR:%d", r); + if ((r = RegSetValueExW(agent_root, L"ProcessID", 0, REG_DWORD, (BYTE*)&process_id, 4)) != ERROR_SUCCESS) + fatal("cannot publish agent master process id ERROR:%d", r); + if ((event_stop_agent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + fatal("cannot create global stop event ERROR:%d", GetLastError()); + if ((r = init_listener()) != 0) + fatal("failed to create server pipes ERROR:%d", r); + agent_listen_loop(); + } + else { /* this is a child process that processes one connection */ + process_connection(pipe); + } + +} + diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h new file mode 100644 index 000000000..36686ffea --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/agent.h @@ -0,0 +1,48 @@ +#include +#include +#define MAX_MESSAGE_SIZE 256 * 1024 + +#define SSH_ROOT L"SOFTWARE\\SSH" +#define SSH_AGENT_ROOT SSH_ROOT L"\\Agent" +#define SSH_KEYS_KEY L"Keys" +#define SSH_KEYS_ROOT SSH_ROOT L"\\" SSH_KEYS_KEY + +#define HEADER_SIZE 4 + +struct agent_connection { + OVERLAPPED ol; + HANDLE connection; + struct { + DWORD num_bytes; + DWORD transferred; + char buf[MAX_MESSAGE_SIZE]; + DWORD buf_size; + } io_buf; + enum { + LISTENING = 0, + READING_HEADER, + READING, + WRITING, + DONE + } state; + enum { + UNKNOWN = 0, + OTHER, + LOCAL_SYSTEM, + SSHD, + NETWORK_SERVICE + } client_process; + HANDLE auth_token; + HANDLE hProfile; +}; + +void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*); +void agent_connection_on_error(struct agent_connection* , DWORD ); +void agent_connection_disconnect(struct agent_connection*); + +void agent_start(BOOL, BOOL, HANDLE); +void agent_shutdown(); +void agent_cleanup_connection(struct agent_connection*); + +int load_config(); +int config_log_level(); \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/agentconfig.c b/contrib/win32/win32compat/ssh-agent/agentconfig.c new file mode 100644 index 000000000..ec261be72 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/agentconfig.c @@ -0,0 +1,132 @@ +#include "includes.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UTIL_H +#include +#endif + +#include "openbsd-compat/sys-queue.h" +#include "xmalloc.h" +#include "ssh.h" +#include "log.h" +#include "buffer.h" +#include "misc.h" +#include "servconf.h" +#include "compat.h" +#include "pathnames.h" +#include "cipher.h" +#include "key.h" +#include "kex.h" +#include "mac.h" +#include "match.h" +#include "channels.h" +#include "groupaccess.h" +#include "canohost.h" +#include "packet.h" +#include "hostfile.h" +#include "auth.h" +#include "myproposal.h" +#include "digest.h" +#include "agent.h" + +#include + +Buffer cfg; +ServerOptions options; +struct passwd *privsep_pw = NULL; +static char *config_file_name = _PATH_SERVER_CONFIG_FILE; +int auth_sock = -1; + +int auth2_methods_valid(const char * c, int i) { + return 1; +} + +int +mm_is_monitor(void) { + return 0; +} + +int kexgex_server(struct ssh * sh) { + return -1; +} + +static +int GetCurrentModulePath(wchar_t *path, int pathSize) +{ + if (GetModuleFileNameW(NULL, path, pathSize)) { + int i; + int lastSlashPos = 0; + + for (i = 0; path[i]; i++) { + if (path[i] == L'/' || path[i] == L'\\') { + lastSlashPos = i; + } + } + + path[lastSlashPos] = 0; + return 0; + } + return -1; +} + +int load_config() { + wchar_t basePath[MAX_PATH] = { 0 }; + wchar_t path[MAX_PATH] = { 0 }; + + /* TODO - account for UNICODE paths*/ + if (GetCurrentModulePath(basePath, MAX_PATH) == -1) + return -1; + + wcsncpy(path, basePath, MAX_PATH); + wcsncat(path, L"/sshd_config", MAX_PATH); + + if ((config_file_name = utf16_to_utf8(path)) == NULL) + return -1; + + buffer_init(&cfg); + initialize_server_options(&options); + load_server_config(config_file_name, &cfg); + parse_server_config(&options, config_file_name, &cfg, NULL); + fill_default_server_options(&options); + + return 0; +} + +int config_log_level() { + return options.log_level; +} + +int pubkey_allowed(struct sshkey* pubkey, wchar_t* wuser, wchar_t* wuser_home) { + struct passwd pw; + int ret; + char *user = NULL, *user_home = NULL; + memset(&pw, 0, sizeof(pw)); + + if ((user_home = utf16_to_utf8(wuser_home)) == NULL || + (user = utf16_to_utf8(wuser)) == NULL) + return 0; + + pw.pw_dir = user_home; + pw.pw_name = user; + ret = user_key_allowed(&pw, pubkey, 1); + free(user); + free(user_home); + return ret; +} \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c new file mode 100644 index 000000000..0cacbe602 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c @@ -0,0 +1,389 @@ +/* +* Author: Manoj Ampalam +* ssh-agent implementation on Windows +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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. +*/ + +#define UMDF_USING_NTSTATUS +#include +#include +#include +#include +#include +#include "agent.h" +#include "agent-request.h" +#include "key.h" + +static void +InitLsaString(LSA_STRING *lsa_string, const char *str) +{ + if (str == NULL) + memset(lsa_string, 0, sizeof(LSA_STRING)); + else { + lsa_string->Buffer = (char *)str; + lsa_string->Length = strlen(str); + lsa_string->MaximumLength = lsa_string->Length + 1; + } +} + +static void +EnablePrivilege(const char *privName, int enabled) +{ + TOKEN_PRIVILEGES tp; + HANDLE hProcToken = NULL; + LUID luid; + + int exitCode = 1; + + if (LookupPrivilegeValueA(NULL, privName, &luid) == FALSE || + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcToken) == FALSE) + goto done; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = enabled ? SE_PRIVILEGE_ENABLED : 0; + + AdjustTokenPrivileges(hProcToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + +done: + if (hProcToken) + CloseHandle(hProcToken); + + return; +} + + +void +LoadProfile(struct agent_connection* con, wchar_t* user, wchar_t* domain) { + PROFILEINFOW profileInfo; + profileInfo.dwFlags = PI_NOUI; + profileInfo.lpProfilePath = NULL; + profileInfo.lpUserName = user; + profileInfo.lpDefaultPath = NULL; + profileInfo.lpServerName = domain; + profileInfo.lpPolicyPath = NULL; + profileInfo.hProfile = NULL; + profileInfo.dwSize = sizeof(profileInfo); + EnablePrivilege("SeBackupPrivilege", 1); + EnablePrivilege("SeRestorePrivilege", 1); + if (LoadUserProfileW(con->auth_token, &profileInfo) == FALSE) + debug("Loading user (%ls,%ls) profile failed ERROR: %d", user, domain, GetLastError()); + else + con->hProfile = profileInfo.hProfile; + EnablePrivilege("SeBackupPrivilege", 0); + EnablePrivilege("SeRestorePrivilege", 0); +} + +#define MAX_USER_LEN 256 +static HANDLE +generate_user_token(wchar_t* user) { + HANDLE lsa_handle = 0, token = 0; + LSA_OPERATIONAL_MODE mode; + ULONG auth_package_id; + NTSTATUS ret, subStatus; + void * logon_info = NULL; + size_t logon_info_size; + LSA_STRING logon_process_name, auth_package_name, originName; + TOKEN_SOURCE sourceContext; + PKERB_INTERACTIVE_PROFILE pProfile = NULL; + LUID logonId; + QUOTA_LIMITS quotas; + DWORD cbProfile; + BOOL domain_user; + wchar_t user_copy[MAX_USER_LEN]; + + /* prep user name - TODO: implment an accurate check if user is domain account*/ + if (wcsnlen(user, MAX_USER_LEN) == MAX_USER_LEN) { + debug("user length is not supported"); + goto done; + } + + if (wcschr(user, L'\\') != NULL) { + wchar_t *un = NULL, *dn = NULL; + DWORD un_len = 0, dn_len = 0; + dn = user; + dn_len = wcschr(user, L'\\') - user; + un = wcschr(user, L'\\') + 1; + un_len = wcsnlen(user, MAX_USER_LEN) - dn_len - 1; + if (dn_len == 0 || un_len == 0) { + debug("cannot get user token - bad user name"); + goto done; + } + memcpy(user_copy, un, un_len * sizeof(wchar_t)); + user_copy[un_len] = L'@'; + memcpy(user_copy + un_len + 1, dn, dn_len * sizeof(wchar_t)); + user_copy[dn_len + 1 + un_len] = L'\0'; + user = user_copy; + } + + domain_user = (wcschr(user, L'@') != NULL) ? TRUE : FALSE; + + InitLsaString(&logon_process_name, "ssh-agent"); + if (domain_user) + InitLsaString(&auth_package_name, MICROSOFT_KERBEROS_NAME_A); + else + InitLsaString(&auth_package_name, "SSH-LSA"); + + InitLsaString(&originName, "sshd"); + if (ret = LsaRegisterLogonProcess(&logon_process_name, &lsa_handle, &mode) != STATUS_SUCCESS) + goto done; + + if (ret = LsaLookupAuthenticationPackage(lsa_handle, &auth_package_name, &auth_package_id) != STATUS_SUCCESS) + goto done; + + if (domain_user) { + KERB_S4U_LOGON *s4u_logon; + logon_info_size = sizeof(KERB_S4U_LOGON); + logon_info_size += (wcslen(user) * 2 + 2); + logon_info = malloc(logon_info_size); + if (logon_info == NULL) + goto done; + s4u_logon = (KERB_S4U_LOGON*)logon_info; + s4u_logon->MessageType = KerbS4ULogon; + s4u_logon->Flags = 0; + s4u_logon->ClientUpn.Length = wcslen(user) * 2; + s4u_logon->ClientUpn.MaximumLength = s4u_logon->ClientUpn.Length; + s4u_logon->ClientUpn.Buffer = (WCHAR*)(s4u_logon + 1); + memcpy(s4u_logon->ClientUpn.Buffer, user, s4u_logon->ClientUpn.Length + 2); + s4u_logon->ClientRealm.Length = 0; + s4u_logon->ClientRealm.MaximumLength = 0; + s4u_logon->ClientRealm.Buffer = 0; + } + else { + logon_info_size = (wcslen(user) + 1)*sizeof(wchar_t); + logon_info = malloc(logon_info_size); + if (logon_info == NULL) + goto done; + memcpy(logon_info, user, logon_info_size); + } + + memcpy(sourceContext.SourceName,"sshagent", sizeof(sourceContext.SourceName)); + + if (AllocateLocallyUniqueId(&sourceContext.SourceIdentifier) != TRUE) + goto done; + + if (ret = LsaLogonUser(lsa_handle, + &originName, + Network, + auth_package_id, + logon_info, + logon_info_size, + NULL, + &sourceContext, + (PVOID*)&pProfile, + &cbProfile, + &logonId, + &token, + "as, + &subStatus) != STATUS_SUCCESS) { + debug("LsaLogonUser failed %d", ret); + goto done; + } + debug3("LsaLogonUser succeeded"); +done: + if (lsa_handle) + LsaDeregisterLogonProcess(lsa_handle); + if (logon_info) + free(logon_info); + if (pProfile) + LsaFreeReturnBuffer(pProfile); + + return token; +} + +#define PUBKEY_AUTH_REQUEST "pubkey" +#define PASSWD_AUTH_REQUEST "password" +#define MAX_USER_NAME_LEN 256 +#define MAX_PW_LEN 128 + +int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + char *user = NULL, *pwd = NULL; + wchar_t userW_buf[MAX_USER_NAME_LEN], pwdW_buf[MAX_PW_LEN]; + wchar_t *userW = userW_buf, *domW = NULL, *pwdW = pwdW_buf, *tmp; + size_t user_len = 0, pwd_len = 0, dom_len = 0; + int r = -1; + HANDLE token = 0, dup_token, client_proc = 0; + ULONG client_pid; + + if (sshbuf_get_cstring(request, &user, &user_len) != 0 || + sshbuf_get_cstring(request, &pwd, &pwd_len) != 0 || + user_len == 0 || + pwd_len == 0 ){ + debug("bad password auth request"); + goto done; + } + + userW[0] = L'\0'; + if (MultiByteToWideChar(CP_UTF8, 0, user, user_len + 1, userW, MAX_USER_NAME_LEN) == 0 || + MultiByteToWideChar(CP_UTF8, 0, pwd, pwd_len + 1, pwdW, MAX_PW_LEN) == 0) { + debug("unable to convert user (%s) or password to UTF-16", user); + goto done; + } + + if ((tmp = wcschr(userW, L'\\')) != NULL) { + domW = userW; + userW = tmp + 1; + *tmp = L'\0'; + + } + else if ((tmp = wcschr(userW, L'@')) != NULL) { + domW = tmp + 1; + *tmp = L'\0'; + } + + if (LogonUserW(userW, domW, pwdW, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) { + debug("failed to logon user"); + goto done; + } + + if ((FALSE == GetNamedPipeClientProcessId(con->connection, &client_pid)) || + ((client_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL) || + (FALSE == DuplicateHandle(GetCurrentProcess(), token, client_proc, &dup_token, TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, DUPLICATE_SAME_ACCESS)) || + (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)) { + debug("failed to duplicate user token"); + goto done; + } + + con->auth_token = token; + LoadProfile(con, userW, domW); + r = 0; +done: + /* TODO Fix this hacky protocol*/ + if ((r == -1) && (sshbuf_put_u8(response, SSH_AGENT_FAILURE) == 0)) + r = 0; + + if (user) + free(user); + if (pwd) + free(pwd); + if (client_proc) + CloseHandle(client_proc); + + return r; +} + +int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + int r = -1; + char *key_blob, *user, *sig, *blob; + size_t key_blob_len, user_len, sig_len, blob_len; + struct sshkey *key = NULL; + HANDLE token = NULL, dup_token = NULL, client_proc = NULL; + wchar_t wuser[MAX_USER_NAME_LEN]; + PWSTR wuser_home = NULL; + ULONG client_pid; + + user = NULL; + if (sshbuf_get_string_direct(request, &key_blob, &key_blob_len) != 0 || + sshbuf_get_cstring(request, &user, &user_len) != 0 || + sshbuf_get_string_direct(request, &sig, &sig_len) != 0 || + sshbuf_get_string_direct(request, &blob, &blob_len) != 0 || + sshkey_from_blob(key_blob, key_blob_len, &key) != 0) { + debug("invalid pubkey auth request"); + goto done; + } + + wuser[0] = L'\0'; + if (MultiByteToWideChar(CP_UTF8, 0, user, user_len + 1, wuser, MAX_USER_NAME_LEN) == 0 || + (token = generate_user_token(wuser)) == 0) { + debug("unable to generate token for user %ls", wuser); + goto done; + } + + con->auth_token = token; + + if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, token, &wuser_home) != S_OK || + pubkey_allowed(key, wuser, wuser_home) != 1) { + debug("given public key is not mapped to user %ls (profile:%ls)", wuser, wuser_home); + goto done; + } + + if (key_verify(key, sig, sig_len, blob, blob_len) != 1) { + debug("signature verification failed"); + goto done; + } + + if ((FALSE == GetNamedPipeClientProcessId(con->connection, &client_pid)) || + ( (client_proc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL) || + (FALSE == DuplicateHandle(GetCurrentProcess(), token, client_proc, &dup_token, TOKEN_QUERY | TOKEN_IMPERSONATE, FALSE, DUPLICATE_SAME_ACCESS)) || + (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0) ) { + debug("failed to authorize user"); + goto done; + } + + { + wchar_t *tmp, *userW, *domW; + userW = wuser; + domW = NULL; + if ((tmp = wcschr(userW, L'\\')) != NULL) { + domW = userW; + userW = tmp + 1; + *tmp = L'\0'; + + } + else if ((tmp = wcschr(userW, L'@')) != NULL) { + domW = tmp + 1; + *tmp = L'\0'; + } + LoadProfile(con, userW, domW); + } + + r = 0; +done: + /* TODO Fix this hacky protocol*/ + if ((r == -1) && (sshbuf_put_u8(response, SSH_AGENT_FAILURE) == 0)) + r = 0; + + if (user) + free(user); + if (key) + sshkey_free(key); + if (wuser_home) + CoTaskMemFree(wuser_home); + if (client_proc) + CloseHandle(client_proc); + return r; +} + +int process_authagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + char *opn; + size_t opn_len; + if (sshbuf_get_string_direct(request, &opn, &opn_len) != 0) { + debug("invalid auth request"); + return -1; + } + + if (opn_len == strlen(PUBKEY_AUTH_REQUEST) && memcmp(opn, PUBKEY_AUTH_REQUEST, opn_len) == 0) + return process_pubkeyauth_request(request, response, con); + else if (opn_len == strlen(PASSWD_AUTH_REQUEST) && memcmp(opn, PASSWD_AUTH_REQUEST, opn_len) == 0) + return process_passwordauth_request(request, response, con); + else { + debug("unknown auth request: %s", opn); + return -1; + } + +} \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/connection.c b/contrib/win32/win32compat/ssh-agent/connection.c new file mode 100644 index 000000000..b45a00522 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/connection.c @@ -0,0 +1,236 @@ +/* + * Author: Manoj Ampalam + * ssh-agent implementation on Windows + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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 "agent.h" +#include "agent-request.h" + +int process_request(struct agent_connection*); + +#define ABORT_CONNECTION_RETURN(c) do { \ + c->state = DONE; \ + agent_cleanup_connection(c); \ + return; \ +} while (0) + +void agent_connection_on_error(struct agent_connection* con, DWORD error) { + ABORT_CONNECTION_RETURN(con); +} + +void agent_connection_on_io(struct agent_connection* con, DWORD bytes, OVERLAPPED* ol) { + + /* process error */ + debug3("connection io %p #bytes:%d state:%d", con, bytes, con->state); + if ((bytes == 0) && (GetOverlappedResult(con->connection, ol, &bytes, FALSE) == FALSE)) + ABORT_CONNECTION_RETURN(con); + + if (con->state == DONE) + DebugBreak(); + + { + switch (con->state) { + case LISTENING: + case WRITING: + /* Writing is done, read next request */ + /* assert on assumption that write always completes on sending all bytes*/ + if (bytes != con->io_buf.num_bytes) + DebugBreak(); + con->state = READING_HEADER; + ZeroMemory(&con->io_buf, sizeof(con->io_buf)); + if (!ReadFile(con->connection, con->io_buf.buf, + HEADER_SIZE, NULL, &con->ol) && (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + break; + case READING_HEADER: + con->io_buf.transferred += bytes; + if (con->io_buf.transferred == HEADER_SIZE) { + con->io_buf.num_bytes = PEEK_U32(con->io_buf.buf); + con->io_buf.transferred = 0; + if (con->io_buf.num_bytes > MAX_MESSAGE_SIZE) + ABORT_CONNECTION_RETURN(con); + + con->state = READING; + if (!ReadFile(con->connection, con->io_buf.buf, + con->io_buf.num_bytes, NULL, &con->ol)&&(GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } + else { + if (!ReadFile(con->connection, con->io_buf.buf + con->io_buf.num_bytes, + HEADER_SIZE - con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } + break; + case READING: + con->io_buf.transferred += bytes; + if (con->io_buf.transferred == con->io_buf.num_bytes) { + if (process_request(con) != 0) { + ABORT_CONNECTION_RETURN(con); + } + con->state = WRITING; + if (!WriteFile(con->connection, con->io_buf.buf, + con->io_buf.num_bytes, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING) ) + ABORT_CONNECTION_RETURN(con); + } + else { + if (!ReadFile(con->connection, con->io_buf.buf + con->io_buf.transferred, + con->io_buf.num_bytes - con->io_buf.transferred, NULL, &con->ol)&& (GetLastError() != ERROR_IO_PENDING)) + ABORT_CONNECTION_RETURN(con); + } + break; + default: + DebugBreak(); + } + } +} + +void agent_connection_disconnect(struct agent_connection* con) { + CancelIoEx(con->connection, NULL); + DisconnectNamedPipe(con->connection); +} + +static int +get_con_client_type(HANDLE pipe) { + int r = -1; + wchar_t *sshd_act = L"NT SERVICE\\SSHD", *ref_dom = NULL; + PSID sshd_sid = NULL; + char system_sid[SECURITY_MAX_SID_SIZE]; + char ns_sid[SECURITY_MAX_SID_SIZE]; + DWORD sshd_sid_len = 0, reg_dom_len = 0, info_len = 0, sid_size; + SID_NAME_USE nuse; + HANDLE token; + TOKEN_USER* info = NULL; + + if (ImpersonateNamedPipeClient(pipe) == FALSE) + return -1; + + if (LookupAccountNameW(NULL, sshd_act, NULL, &sshd_sid_len, NULL, ®_dom_len, &nuse) == TRUE || + (sshd_sid = malloc(sshd_sid_len)) == NULL || + (ref_dom = (wchar_t*)malloc(reg_dom_len * 2)) == NULL || + LookupAccountNameW(NULL, sshd_act, sshd_sid, &sshd_sid_len, ref_dom, ®_dom_len, &nuse) == FALSE || + OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE || + GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || + (info = (TOKEN_USER*)malloc(info_len)) == NULL || + GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE) + goto done; + + sid_size = SECURITY_MAX_SID_SIZE; + if (CreateWellKnownSid(WinLocalSystemSid, NULL, system_sid, &sid_size) == FALSE) + goto done; + sid_size = SECURITY_MAX_SID_SIZE; + if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE) + goto done; + + if (EqualSid(info->User.Sid, system_sid)) + r = LOCAL_SYSTEM; + else if (EqualSid(info->User.Sid, sshd_sid)) + r = SSHD; + else if (EqualSid(info->User.Sid, ns_sid)) + r = NETWORK_SERVICE; + else + r = OTHER; + + debug2("client type: %d", r); +done: + if (sshd_sid) + free(sshd_sid); + if (ref_dom) + free(ref_dom); + if (info) + free(info); + RevertToSelf(); + return r; +} + +/* TODO - move this to common header*/ +#define SSH_AGENT_AUTHENTICATE 100 + +static int +process_request(struct agent_connection* con) { + int r = -1; + struct sshbuf *request = NULL, *response = NULL; + + if (con->client_process == UNKNOWN) + if ((con->client_process = get_con_client_type(con->connection)) == -1) + goto done; + + + request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); + response = sshbuf_new(); + if ((request == NULL) || (response == NULL)) + goto done; + + { + u_char type; + + if (sshbuf_get_u8(request, &type) != 0) + return -1; + debug("process agent request type %d", type); + + switch (type) { + case SSH2_AGENTC_ADD_IDENTITY: + r = process_add_identity(request, response, con); + break; + case SSH2_AGENTC_REQUEST_IDENTITIES: + r = process_request_identities(request, response, con); + break; + case SSH2_AGENTC_SIGN_REQUEST: + r = process_sign_request(request, response, con); + break; + case SSH2_AGENTC_REMOVE_IDENTITY: + r = process_remove_key(request, response, con); + break; + case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: + r = process_remove_all(request, response, con); + break; + case SSH_AGENT_AUTHENTICATE: + r = process_authagent_request(request, response, con); + break; + default: + debug("unknown agent request %d", type); + r = -1; + break; + } + } + +done: + if (request) + sshbuf_free(request); + + ZeroMemory(&con->io_buf, sizeof(con->io_buf)); + if (r == 0) { + POKE_U32(con->io_buf.buf, sshbuf_len(response)); + memcpy(con->io_buf.buf + 4, sshbuf_ptr(response), sshbuf_len(response)); + con->io_buf.num_bytes = sshbuf_len(response) + 4; + } + + if (response) + sshbuf_free(response); + + return r; +} \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/keyagent-request.c b/contrib/win32/win32compat/ssh-agent/keyagent-request.c new file mode 100644 index 000000000..08225ac27 --- /dev/null +++ b/contrib/win32/win32compat/ssh-agent/keyagent-request.c @@ -0,0 +1,438 @@ +/* + * Author: Manoj Ampalam + * ssh-agent implementation on Windows + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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 "agent.h" +#include "agent-request.h" +#include + +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_NAME 16383 + +static int +get_user_root(struct agent_connection* con, HKEY *root){ + int r = 0; + *root = NULL; + if (ImpersonateNamedPipeClient(con->connection) == FALSE) + return -1; + + if (con->client_process > OTHER) + *root = HKEY_LOCAL_MACHINE; + else if (RegOpenCurrentUser(KEY_ALL_ACCESS, root) != ERROR_SUCCESS) + r = -1; + + if (*root == NULL) + debug("cannot connect to user's registry root"); + RevertToSelf(); + return r; +} + +static int +convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **eblob, DWORD *eblen, int encrypt) { + int success = 0; + DATA_BLOB in, out; + + if (con->client_process == OTHER) + if (ImpersonateNamedPipeClient(con->connection) == FALSE) + return -1; + + in.cbData = blen; + in.pbData = (char*)blob; + out.cbData = 0; + out.pbData = NULL; + + if (encrypt) { + if (!CryptProtectData(&in, NULL, NULL, 0, NULL, 0, &out)) { + debug("cannot encrypt data"); + goto done; + } + } + else { + if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) { + debug("cannot decrypt data"); + goto done; + } + } + + *eblob = malloc(out.cbData); + if (*eblob == NULL) + goto done; + + memcpy(*eblob, out.pbData, out.cbData); + *eblen = out.cbData; + success = 1; +done: + if (out.pbData) + LocalFree(out.pbData); + if (con->client_process == OTHER) + RevertToSelf(); + return success? 0: -1; +} + +#define REG_KEY_SDDL L"D:P(A;; GA;;; SY)(A;; GA;;; BA)" + +int +process_add_identity(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + struct sshkey* key = NULL; + int r = 0, blob_len, eblob_len, request_invalid = 0, success = 0; + size_t comment_len, pubkey_blob_len; + u_char *pubkey_blob = NULL; + char *thumbprint = NULL, *comment; + const char *blob; + char* eblob = NULL; + HKEY reg = 0, sub = 0, user_root = 0; + SECURITY_ATTRIBUTES sa; + + /* parse input request */ + blob = sshbuf_ptr(request); + if (sshkey_private_deserialize(request, &key) != 0 || + (blob_len = (sshbuf_ptr(request) - blob) & 0xffffffff) == 0 || + sshbuf_peek_string_direct(request, &comment, &comment_len) != 0) { + debug("key add request is invalid"); + request_invalid = 1; + goto done; + } + + memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); + sa.nLength = sizeof(sa); + if ((!ConvertStringSecurityDescriptorToSecurityDescriptorW(REG_KEY_SDDL, SDDL_REVISION_1, &sa.lpSecurityDescriptor, &sa.nLength)) || + sshkey_to_blob(key, &pubkey_blob, &pubkey_blob_len) != 0 || + convert_blob(con, blob, blob_len, &eblob, &eblob_len, 1) != 0 || + ((thumbprint = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL) || + get_user_root(con, &user_root) != 0 || + RegCreateKeyExW(user_root, SSH_KEYS_ROOT, 0, 0, 0, KEY_WRITE | KEY_WOW64_64KEY, &sa, ®, NULL) != 0 || + RegCreateKeyExA(reg, thumbprint, 0, 0, 0, KEY_WRITE | KEY_WOW64_64KEY, &sa, &sub, NULL) != 0 || + RegSetValueExW(sub, NULL, 0, REG_BINARY, eblob, eblob_len) != 0 || + RegSetValueExW(sub, L"pub", 0, REG_BINARY, pubkey_blob, pubkey_blob_len) != 0 || + RegSetValueExW(sub, L"type", 0, REG_DWORD, (BYTE*)&key->type, 4) != 0 || + RegSetValueExW(sub, L"comment", 0, REG_BINARY, comment, comment_len) != 0 ) { + debug("failed to add key to store"); + goto done; + } + + debug("added key to store"); + success = 1; +done: + r = 0; + if (request_invalid) + r = -1; + else if (sshbuf_put_u8(response, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE) != 0) + r = -1; + + /* delete created reg key if not succeeded*/ + if ((success == 0) && reg && thumbprint) + RegDeleteKeyExA(reg, thumbprint, KEY_WOW64_64KEY, 0); + + if (eblob) + free(eblob); + if (sa.lpSecurityDescriptor) + LocalFree(sa.lpSecurityDescriptor); + if (key) + sshkey_free(key); + if (thumbprint) + free(thumbprint); + if (user_root) + RegCloseKey(user_root); + if (reg) + RegCloseKey(reg); + if (sub) + RegCloseKey(sub); + if (pubkey_blob) + free(pubkey_blob); + return r; +} + +static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen, + const u_char *blob, size_t blen, u_int flags, struct agent_connection* con) { + HKEY reg = 0, sub = 0, user_root = 0; + int r = 0, success = 0; + struct sshkey* prikey = NULL; + char *thumbprint = NULL, *regdata = NULL; + DWORD regdatalen = 0, keyblob_len = 0; + struct sshbuf* tmpbuf = NULL; + char *keyblob = NULL; + + *sig = NULL; + *siglen = 0; + + if ((thumbprint = sshkey_fingerprint(pubkey, SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL || + get_user_root(con, &user_root) != 0 || + RegOpenKeyExW(user_root, SSH_KEYS_ROOT, + 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY | KEY_ENUMERATE_SUB_KEYS, ®) != 0 || + RegOpenKeyExA(reg, thumbprint, 0, + STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY, &sub) != 0 || + RegQueryValueExW(sub, NULL, 0, NULL, NULL, ®datalen) != ERROR_SUCCESS || + (regdata = malloc(regdatalen)) == NULL || + RegQueryValueExW(sub, NULL, 0, NULL, regdata, ®datalen) != ERROR_SUCCESS || + convert_blob(con, regdata, regdatalen, &keyblob, &keyblob_len, FALSE) != 0 || + (tmpbuf = sshbuf_from(keyblob, keyblob_len)) == NULL) + goto done; + + if (sshkey_private_deserialize(tmpbuf, &prikey) != 0 || + sshkey_sign(prikey, sig, siglen, blob, blen, NULL, 0) != 0) { + debug("cannot sign using retrieved key"); + goto done; + } + + success = 1; + +done: + if (keyblob) + free(keyblob); + if (regdata) + free(regdata); + if (tmpbuf) + sshbuf_free(tmpbuf); + if (prikey) + sshkey_free(prikey); + if (thumbprint) + free(thumbprint); + if (user_root) + RegCloseKey(user_root); + if (reg) + RegCloseKey(reg); + if (sub) + RegCloseKey(sub); + + return success ? 0 : -1; +} + +int +process_sign_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + u_char *blob, *data, *signature = NULL; + size_t blen, dlen, slen = 0; + u_int flags = 0; + int r, request_invalid = 0, success = 0; + struct sshkey *key = NULL; + + if (sshbuf_get_string_direct(request, &blob, &blen) != 0 || + sshbuf_get_string_direct(request, &data, &dlen) != 0 || + sshbuf_get_u32(request, &flags) != 0 || + sshkey_from_blob(blob, blen, &key) != 0) { + debug("sign request is invalid"); + request_invalid = 1; + goto done; + } + + /* TODO - flags?*/ + + if (sign_blob(key, &signature, &slen, data, dlen, 0, con) != 0) + goto done; + + success = 1; +done: + r = 0; + if (request_invalid) + r = -1; + else { + if (success) { + if (sshbuf_put_u8(response, SSH2_AGENT_SIGN_RESPONSE) != 0 || + sshbuf_put_string(response, signature, slen) != 0) { + r = -1; + } + } + else + if (sshbuf_put_u8(response, SSH_AGENT_FAILURE) != 0) + r = -1; + } + + if (key) + sshkey_free(key); + if (signature) + free(signature); + return r; +} + +int +process_remove_key(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + HKEY user_root = 0, root = 0; + char *blob, *thumbprint = NULL; + size_t blen; + int r = 0, success = 0, request_invalid = 0; + struct sshkey *key = NULL; + + if (sshbuf_get_string_direct(request, &blob, &blen) != 0 || + sshkey_from_blob(blob, blen, &key) != 0) { + request_invalid = 1; + goto done; + } + + if ((thumbprint = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL || + get_user_root(con, &user_root) != 0 || + RegOpenKeyExW(user_root, SSH_KEYS_ROOT, 0, + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_64KEY, &root) != 0 || + RegDeleteTreeA(root, thumbprint) != 0) + goto done; + success = 1; +done: + r = 0; + if (request_invalid) + r = -1; + else if (sshbuf_put_u8(response, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE) != 0) + r = -1; + + if (key) + sshkey_free(key); + if (user_root) + RegCloseKey(user_root); + if (root) + RegCloseKey(root); + if (thumbprint) + free(thumbprint); + return r; +} +int +process_remove_all(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + HKEY user_root = 0, root = 0; + int r = 0; + + if (get_user_root(con, &user_root) != 0 || + RegOpenKeyExW(user_root, SSH_ROOT, 0, + DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_64KEY, &root) != 0) { + goto done; + } + + RegDeleteTreeW(root, SSH_KEYS_KEY); +done: + r = 0; + if (sshbuf_put_u8(response, SSH_AGENT_SUCCESS) != 0) + r = -1; + + if (user_root) + RegCloseKey(user_root); + if (root) + RegCloseKey(root); + return r; +} + +int +process_request_identities(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + int count = 0, index = 0, success = 0, r = 0; + HKEY root = NULL, sub = NULL, user_root = 0; + char* count_ptr = NULL; + wchar_t sub_name[MAX_KEY_LENGTH]; + DWORD sub_name_len = MAX_KEY_LENGTH; + char *pkblob = NULL, *comment = NULL; + DWORD regdatalen = 0, commentlen = 0, key_count = 0; + struct sshbuf* identities; + + if ((identities = sshbuf_new()) == NULL) + goto done; + + if ( get_user_root(con, &user_root) != 0 || + RegOpenKeyExW(user_root, SSH_KEYS_ROOT, 0, STANDARD_RIGHTS_READ | KEY_ENUMERATE_SUB_KEYS | KEY_WOW64_64KEY, &root) != 0) { + success = 1; + goto done; + } + + while (1) { + sub_name_len = MAX_KEY_LENGTH; + if (sub) { + RegCloseKey(sub); + sub = NULL; + } + if (RegEnumKeyExW(root, index++, sub_name, &sub_name_len, NULL, NULL, NULL, NULL) == 0) { + if (RegOpenKeyExW(root, sub_name, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &sub) == 0 && + RegQueryValueExW(sub, L"pub", 0, NULL, NULL, ®datalen) == 0 && + RegQueryValueExW(sub, L"comment", 0, NULL, NULL, &commentlen) == 0) { + if (pkblob) + free(pkblob); + if (comment) + free(comment); + pkblob = NULL; + comment = NULL; + + if ((pkblob = malloc(regdatalen)) == NULL || + (comment = malloc(commentlen)) == NULL || + RegQueryValueExW(sub, L"pub", 0, NULL, pkblob, ®datalen) != 0 || + RegQueryValueExW(sub, L"comment", 0, NULL, comment, &commentlen) != 0 || + sshbuf_put_string(identities, pkblob, regdatalen) != 0 || + sshbuf_put_string(identities, comment, commentlen) != 0) + goto done; + + key_count++; + } + } + else + break; + + } + + success = 1; +done: + r = 0; + if (success) { + if (sshbuf_put_u8(response, SSH2_AGENT_IDENTITIES_ANSWER) != 0 || + sshbuf_put_u32(response, key_count) != 0 || + sshbuf_putb(response, identities) != 0) + goto done; + } + else + r = -1; + + if (pkblob) + free(pkblob); + if (comment) + free(comment); + if (identities) + sshbuf_free(identities); + if (user_root) + RegCloseKey(user_root); + if (root) + RegCloseKey(root); + if (sub) + RegCloseKey(sub); + return r; +} + + +int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) { + u_char type; + + if (sshbuf_get_u8(request, &type) != 0) + return -1; + debug2("process key agent request type %d", type); + + switch (type) { + case SSH2_AGENTC_ADD_IDENTITY: + return process_add_identity(request, response, con); + case SSH2_AGENTC_REQUEST_IDENTITIES: + return process_request_identities(request, response, con); + case SSH2_AGENTC_SIGN_REQUEST: + return process_sign_request(request, response, con); + case SSH2_AGENTC_REMOVE_IDENTITY: + return process_remove_key(request, response, con); + case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: + return process_remove_all(request, response, con); + default: + debug("unknown key agent request %d", type); + return -1; + } +} \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh_config/ssh_config b/contrib/win32/win32compat/ssh_config/ssh_config new file mode 100644 index 000000000..42d6699b1 --- /dev/null +++ b/contrib/win32/win32compat/ssh_config/ssh_config @@ -0,0 +1,50 @@ +# $OpenBSD: ssh_config,v 1.26 2010/01/11 01:39:46 dtucker Exp $ + +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# Site-wide defaults for some commonly used options. For a comprehensive +# list of available options, their meanings and defaults, please see the +# ssh_config(5) man page. + +# Host * +# ForwardAgent no +# ForwardX11 no +# RhostsRSAAuthentication no +# RSAAuthentication yes +# PasswordAuthentication yes +# HostbasedAuthentication no +# GSSAPIAuthentication no +# GSSAPIDelegateCredentials no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# Port 22 +# Protocol 2,1 +# Cipher 3des +# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc +# MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 +# EscapeChar ~ +# Tunnel no +# TunnelDevice any:any +# PermitLocalCommand no +# VisualHostKey no +# ProxyCommand ssh -q -W %h:%p gateway.example.com +#UsePrivilegeSeparation no +PubkeyAcceptedKeyTypes ssh-ed25519*,ssh-rsa*,ssh-dss*,ecdsa-sha2* + diff --git a/contrib/win32/win32compat/ssh_config/sshd_config b/contrib/win32/win32compat/ssh_config/sshd_config new file mode 100644 index 000000000..5b9152606 --- /dev/null +++ b/contrib/win32/win32compat/ssh_config/sshd_config @@ -0,0 +1,122 @@ +# $OpenBSD: sshd_config,v 1.84 2011/05/23 03:30:07 djm Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options override the +# default value. + +#Port 22 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +# The default requires explicit activation of protocol 1 +#Protocol 2 + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key +#HostKey /etc/ssh/ssh_host_ecdsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 1024 + +# Logging +# obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +#PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#RSAAuthentication yes +#PubkeyAuthentication yes + +# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +# but this is overridden so installations will only check .ssh/authorized_keys +AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +#UsePAM no + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 +#PermitTunnel no +#ChrootDirectory none + +# no default banner path +#Banner none + +# override default of no subsystems +#Subsystem sftp /usr/libexec/sftp-server +Subsystem sftp /win32openssh/bin/sftp-server.exe + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# ForceCommand cvs server diff --git a/contrib/win32/win32compat/termio.c b/contrib/win32/win32compat/termio.c new file mode 100644 index 000000000..4ae3be65e --- /dev/null +++ b/contrib/win32/win32compat/termio.c @@ -0,0 +1,205 @@ +#include +#include "w32fd.h" +#include "tncon.h" +#include "inc\defs.h" +#include "inc\utf.h" + +#define TERM_IO_BUF_SIZE 2048 + +struct io_status { + DWORD to_transfer; + DWORD transferred; + DWORD error; +}; + +static struct io_status read_status, write_status; + +static VOID CALLBACK ReadAPCProc( + _In_ ULONG_PTR dwParam + ) { + struct w32_io* pio = (struct w32_io*)dwParam; + debug3("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred, + pio->read_details.pending, read_status.error); + pio->read_details.error = read_status.error; + pio->read_details.remaining = read_status.transferred; + pio->read_details.completed = 0; + pio->read_details.pending = FALSE; + WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE); + CloseHandle(pio->read_overlapped.hEvent); + pio->read_overlapped.hEvent = 0; +} + +static DWORD WINAPI ReadThread( + _In_ LPVOID lpParameter + ) { + struct w32_io* pio = (struct w32_io*)lpParameter; + debug3("TermRead thread, io:%p", pio); + memset(&read_status, 0, sizeof(read_status)); + if (!ReadFile(WINHANDLE(pio), pio->read_details.buf, + pio->read_details.buf_size, &read_status.transferred, NULL)) { + read_status.error = GetLastError(); + debug("TermRead thread - ReadFile failed %d, io:%p", GetLastError(), pio); + } + + if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) { + debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + pio->read_details.pending = FALSE; + pio->read_details.error = GetLastError(); + DebugBreak(); + } + return 0; +} + +static DWORD WINAPI ReadConsoleThread( + _In_ LPVOID lpParameter +) { + int nBytesReturned = 0; + + struct w32_io* pio = (struct w32_io*)lpParameter; + + debug3("TermRead thread, io:%p", pio); + memset(&read_status, 0, sizeof(read_status)); + + while (nBytesReturned == 0) { + nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio), + pio->read_details.buf, pio->read_details.buf_size); + } + + read_status.transferred = nBytesReturned; + + if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) { + debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + pio->read_details.pending = FALSE; + pio->read_details.error = GetLastError(); + DebugBreak(); + } + + return 0; +} + +int +termio_initiate_read(struct w32_io* pio) { + HANDLE read_thread; + + debug3("TermRead initiate io:%p", pio); + + if (pio->read_details.buf_size == 0) { + pio->read_details.buf = malloc(TERM_IO_BUF_SIZE); + if (pio->read_details.buf == NULL) { + errno = ENOMEM; + return -1; + } + pio->read_details.buf_size = TERM_IO_BUF_SIZE; + } + + read_thread = CreateThread(NULL, 0, ReadConsoleThread, pio, 0, NULL); + if (read_thread == NULL) { + errno = errno_from_Win32Error(GetLastError()); + debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + return -1; + } + + pio->read_overlapped.hEvent = read_thread; + pio->read_details.pending = TRUE; + return 0; +} + +static VOID CALLBACK WriteAPCProc( + _In_ ULONG_PTR dwParam + ) { + struct w32_io* pio = (struct w32_io*)dwParam; + debug3("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred, + pio->write_details.pending, write_status.error); + pio->write_details.error = write_status.error; + pio->write_details.remaining -= write_status.transferred; + /*TODO- assert that reamining is 0 by now*/ + pio->write_details.completed = 0; + pio->write_details.pending = FALSE; + WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE); + CloseHandle(pio->write_overlapped.hEvent); + pio->write_overlapped.hEvent = 0; +} + +static DWORD WINAPI WriteThread( + _In_ LPVOID lpParameter + ) { + struct w32_io* pio = (struct w32_io*)lpParameter; + char *respbuf = NULL; + size_t resplen = 0; + DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT; + debug3("TermWrite thread, io:%p", pio); + + /* decide to call parsing engine or directly write to console + * doing the following trick to decide - + * if console in handle is set to process Ctrl+C, then it is likely + * serving a PTY enabled session + */ + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes); + if (dwSavedAttributes & ENABLE_PROCESSED_INPUT) { + /* convert stream to utf16 and dump on console */ + pio->write_details.buf[write_status.to_transfer] = '\0'; + wchar_t* t = utf8_to_utf16(pio->write_details.buf); + WriteConsoleW(WINHANDLE(pio), t, wcslen(t), 0, 0); + free(t); + write_status.transferred = write_status.to_transfer; + } else { + + telProcessNetwork(pio->write_details.buf, write_status.to_transfer, &respbuf, &resplen); + /*TODO - respbuf is not null in some cases, this needs to be returned back via read stream*/ + write_status.transferred = write_status.to_transfer; + } + + if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) { + debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); + pio->write_details.pending = FALSE; + pio->write_details.error = GetLastError(); + DebugBreak(); + } + return 0; +} + +int +termio_initiate_write(struct w32_io* pio, DWORD num_bytes) { + HANDLE write_thread; + + debug3("TermWrite initiate io:%p", pio); + memset(&write_status, 0, sizeof(write_status)); + write_status.to_transfer = num_bytes; + write_thread = CreateThread(NULL, 0, WriteThread, pio, 0, NULL); + if (write_thread == NULL) { + errno = errno_from_Win32Error(GetLastError()); + debug("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio); + return -1; + } + + pio->write_overlapped.hEvent = write_thread; + pio->write_details.pending = TRUE; + return 0; +} + + +int termio_close(struct w32_io* pio) { + debug2("termio_close - pio:%p", pio); + HANDLE h; + + CancelIoEx(WINHANDLE(pio), NULL); + /* If io is pending, let write worker threads exit. The read thread is blocked so terminate it.*/ + if (pio->read_details.pending) + TerminateThread(pio->read_overlapped.hEvent, 0); + if (pio->write_details.pending) + WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE); + /* drain queued APCs */ + SleepEx(0, TRUE); + if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed + CloseHandle(WINHANDLE(pio)); + + if (pio->read_details.buf) + free(pio->read_details.buf); + + if (pio->write_details.buf) + free(pio->write_details.buf); + + free(pio); + } + return 0; +} diff --git a/contrib/win32/win32compat/tncon.c b/contrib/win32/win32compat/tncon.c new file mode 100644 index 000000000..7df7eb24c --- /dev/null +++ b/contrib/win32/win32compat/tncon.c @@ -0,0 +1,626 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* tncon.c + * + * Console reading calls for building an emulator over Windows Console. MS win32 port of ssh.exe client uses it. + * +*/ +#include +#include +#include +#include + + +#include + +#include "ansiprsr.h" +#include "tncon.h" +#include "tnnet.h" + +extern bool gbVTAppMode; + +char *glob_out = NULL ; +int glob_outlen = 0; +int glob_space = 0; + +unsigned char NAWSSTR[] = { "\xff\xfa\x1f\x00\x00\x00\x00\xff\xf0" }; + +extern int ScreenY; +extern int ScreenX; + +extern int ScrollTop; +extern int ScrollBottom; + +/* terminal global switches*/ +TelParams Parameters = { + 0, // int fLogging; + NULL, //FILE *fplogfile; + NULL, //char *pInputFile; + NULL, // char *szDebugInputFile; + FALSE, //BOOL fDebugWait; + 0, //int timeOut; + 0, //int fLocalEcho; + 0, //int fTreatLFasCRLF; + 0, //int fSendCROnly; + ENUM_LF, //int nReceiveCRLF; + '`', //char sleepChar; + '\035', //char menuChar; // CTRL-] + 0, //SOCKET Socket; + FALSE, //BOOL bVT100Mode; + "\x01", //char *pAltKey; +}; +TelParams* pParams = &Parameters; + +// For our case, in NetWriteString2(), we do not use socket, but write the out going data to +// a global buffer setup by ReadConsoleForTermEmul() function below +int NetWriteString2(SOCKET sock, char* source, size_t len, int options) +{ + while (len > 0) { + if (glob_outlen >= glob_space) + return glob_outlen; + *glob_out++ = *source++ ; + len--; + glob_outlen++; + } + + return glob_outlen; +} + +BOOL DataAvailable(HANDLE h) +{ + DWORD dwRet = WaitForSingleObject(h, INFINITE); + if(dwRet == WAIT_OBJECT_0) + return TRUE; + + if(dwRet == WAIT_FAILED) + return FALSE; + + return FALSE; +} + +void queue_terminal_window_change_event(); + +int ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen) +{ + HANDLE hHandle[] = { hInput, NULL }; + DWORD nHandle = 1; + DWORD dwInput = 0; + DWORD dwControlKeyState = 0; + DWORD rc = 0; + + unsigned char szResponse[50]; + unsigned char octets[20]; + + char aChar = 0; + + INPUT_RECORD InputRecord; + + BOOL bCapsOn = FALSE; + BOOL bShift = FALSE; + + glob_out = destin; + glob_space = destinlen; + glob_outlen = 0; + + while (DataAvailable(hInput)) + { + if (glob_outlen >= destinlen) + return glob_outlen; + + ReadConsoleInput(hInput, &InputRecord, 1, &dwInput); + + switch (InputRecord.EventType) + { + case WINDOW_BUFFER_SIZE_EVENT: + queue_terminal_window_change_event(); + break; + + case FOCUS_EVENT: + case MENU_EVENT: + break; + + case KEY_EVENT: + bCapsOn = (InputRecord.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON); + bShift = (InputRecord.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED); + dwControlKeyState = InputRecord.Event.KeyEvent.dwControlKeyState & + ~(CAPSLOCK_ON | ENHANCED_KEY | NUMLOCK_ON | SCROLLLOCK_ON); + + if (InputRecord.Event.KeyEvent.bKeyDown) + { + int n = WideCharToMultiByte( + CP_UTF8, + 0, + &(InputRecord.Event.KeyEvent.uChar.UnicodeChar), + 1, + (LPSTR)octets, + 20, + NULL, + NULL); + + if (pParams->fLocalEcho) { + ConWriteString((char *)octets, n); + } + + switch (InputRecord.Event.KeyEvent.uChar.UnicodeChar) + { + case 0xd: + if (pParams->nReceiveCRLF == ENUM_LF) + NetWriteString2(pParams->Socket, "\r", 1, 0); + else + NetWriteString2(pParams->Socket, "\r\n", 2, 0); + break; + + case VK_ESCAPE: + NetWriteString2(pParams->Socket, (char *)ESCAPE_KEY, 1, 0); + break; + + default: + switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) + { + case VK_UP: + NetWriteString2(pParams->Socket, (char *)(gbVTAppMode ? APP_UP_ARROW : UP_ARROW), 3, 0); + break; + case VK_DOWN: + NetWriteString2(pParams->Socket, (char *)(gbVTAppMode ? APP_DOWN_ARROW : DOWN_ARROW), 3, 0); + break; + case VK_RIGHT: + NetWriteString2(pParams->Socket, (char *)(gbVTAppMode ? APP_RIGHT_ARROW : RIGHT_ARROW), 3, 0); + break; + case VK_LEFT: + NetWriteString2(pParams->Socket, (char *)(gbVTAppMode ? APP_LEFT_ARROW : LEFT_ARROW), 3, 0); + break; + case VK_END: + NetWriteString2(pParams->Socket, (char *)SELECT_KEY, 4, 0); + break; + case VK_HOME: + NetWriteString2(pParams->Socket, (char *)FIND_KEY, 4, 0); + break; + case VK_INSERT: + NetWriteString2(pParams->Socket, (char *)INSERT_KEY, 4, 0); + break; + case VK_DELETE: + NetWriteString2(pParams->Socket, (char *)REMOVE_KEY, 4, 0); + break; + case VK_BACK: + NetWriteString2(pParams->Socket, (char *)BACKSPACE_KEY, 1, 0); + break; + case VK_TAB: + if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_TAB_KEY, 3, 0); + else + NetWriteString2(pParams->Socket, (char *)octets, n, 0); + break; + case VK_ESCAPE: + NetWriteString2(pParams->Socket, (char *)ESCAPE_KEY, 1, 0); + break; + case VK_SHIFT: + case VK_CONTROL: + case VK_CAPITAL: + // NOP on these + break; + case VK_F1: + if (dwControlKeyState == 0) + { + NetWriteString2(pParams->Socket, (char *)PF1_KEY, strlen(PF1_KEY), 0); + } + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF1_KEY, strlen(SHIFT_PF1_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF1_KEY, strlen(CTRL_PF1_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF1_KEY, strlen(ALT_PF1_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF1_KEY, strlen(SHIFT_ALT_CTRL_PF1_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF1_KEY, strlen(ALT_CTRL_PF1_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF1_KEY, strlen(SHIFT_ALT_PF1_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF1_KEY, strlen(SHIFT_CTRL_PF1_KEY), 0); + break; + case VK_F2: + if (dwControlKeyState == 0) + { + NetWriteString2(pParams->Socket, (char *)PF2_KEY, strlen(PF2_KEY), 0); + } + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF2_KEY, strlen(SHIFT_PF2_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF2_KEY, strlen(CTRL_PF2_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF2_KEY, strlen(ALT_PF2_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF2_KEY, strlen(SHIFT_ALT_CTRL_PF2_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF2_KEY, strlen(ALT_CTRL_PF2_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF2_KEY, strlen(SHIFT_ALT_PF2_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF2_KEY, strlen(SHIFT_CTRL_PF2_KEY), 0); + break; + case VK_F3: + if (dwControlKeyState == 0) + { + NetWriteString2(pParams->Socket, (char *)PF3_KEY, strlen(PF3_KEY), 0); + } + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF3_KEY, strlen(SHIFT_PF3_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF3_KEY, strlen(CTRL_PF3_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF3_KEY, strlen(ALT_PF3_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF3_KEY, strlen(SHIFT_ALT_CTRL_PF3_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF3_KEY, strlen(ALT_CTRL_PF3_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF3_KEY, strlen(SHIFT_ALT_PF3_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF3_KEY, strlen(SHIFT_CTRL_PF3_KEY), 0); + break; + case VK_F4: + if (dwControlKeyState == 0) + { + NetWriteString2(pParams->Socket, (char *)PF4_KEY, strlen(PF4_KEY), 0); + } + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF4_KEY, strlen(SHIFT_PF4_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF4_KEY, strlen(CTRL_PF4_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF4_KEY, strlen(ALT_PF4_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF4_KEY, strlen(SHIFT_ALT_CTRL_PF4_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF4_KEY, strlen(ALT_CTRL_PF4_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF4_KEY, strlen(SHIFT_ALT_PF4_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF4_KEY, strlen(SHIFT_CTRL_PF4_KEY), 0); + break; + case VK_F5: + if (dwControlKeyState == 0) + { + NetWriteString2(pParams->Socket, (char *)PF5_KEY, strlen(PF5_KEY), 0); + } + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF5_KEY, strlen(SHIFT_PF5_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF5_KEY, strlen(CTRL_PF5_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF5_KEY, strlen(ALT_PF5_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF5_KEY, strlen(SHIFT_ALT_CTRL_PF5_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF5_KEY, strlen(ALT_CTRL_PF5_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF5_KEY, strlen(SHIFT_ALT_PF5_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF5_KEY, strlen(SHIFT_CTRL_PF5_KEY), 0); + break; + case VK_F6: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF6_KEY, strlen(PF6_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF6_KEY, strlen(SHIFT_PF6_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF6_KEY, strlen(CTRL_PF6_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF6_KEY, strlen(ALT_PF6_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF6_KEY, strlen(SHIFT_ALT_CTRL_PF6_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF6_KEY, strlen(ALT_CTRL_PF6_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF6_KEY, strlen(SHIFT_ALT_PF6_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF6_KEY, strlen(SHIFT_CTRL_PF6_KEY), 0); + break; + case VK_F7: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF7_KEY, strlen(PF7_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF7_KEY, strlen(SHIFT_PF7_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF7_KEY, strlen(CTRL_PF7_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF7_KEY, strlen(ALT_PF7_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF7_KEY, strlen(SHIFT_ALT_CTRL_PF7_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF7_KEY, strlen(ALT_CTRL_PF7_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF7_KEY, strlen(SHIFT_ALT_PF7_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF7_KEY, strlen(SHIFT_CTRL_PF7_KEY), 0); + break; + case VK_F8: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF8_KEY, strlen(PF8_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF8_KEY, strlen(SHIFT_PF8_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF8_KEY, strlen(CTRL_PF8_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF8_KEY, strlen(ALT_PF8_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF8_KEY, strlen(SHIFT_ALT_CTRL_PF8_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF8_KEY, strlen(ALT_CTRL_PF8_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF8_KEY, strlen(SHIFT_ALT_PF8_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF8_KEY, strlen(SHIFT_CTRL_PF8_KEY), 0); + break; + case VK_F9: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF9_KEY, strlen(PF9_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF9_KEY, strlen(SHIFT_PF9_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF9_KEY, strlen(CTRL_PF9_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF9_KEY, strlen(ALT_PF9_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF9_KEY, strlen(SHIFT_ALT_CTRL_PF9_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF9_KEY, strlen(ALT_CTRL_PF9_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF9_KEY, strlen(SHIFT_ALT_PF9_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF9_KEY, strlen(SHIFT_CTRL_PF9_KEY), 0); + break; + case VK_F10: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF10_KEY, strlen(PF10_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF10_KEY, strlen(SHIFT_PF10_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF10_KEY, strlen(CTRL_PF10_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF10_KEY, strlen(ALT_PF10_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF10_KEY, strlen(SHIFT_ALT_CTRL_PF10_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF10_KEY, strlen(ALT_CTRL_PF10_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF10_KEY, strlen(SHIFT_ALT_PF10_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF10_KEY, strlen(SHIFT_CTRL_PF10_KEY), 0); + break; + case VK_F11: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF11_KEY, strlen(PF11_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF11_KEY, strlen(SHIFT_PF11_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF11_KEY, strlen(CTRL_PF11_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF11_KEY, strlen(ALT_PF11_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF11_KEY, strlen(SHIFT_ALT_CTRL_PF11_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF11_KEY, strlen(ALT_CTRL_PF11_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF11_KEY, strlen(SHIFT_ALT_PF11_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF11_KEY, strlen(SHIFT_CTRL_PF11_KEY), 0); + break; + case VK_F12: + if (dwControlKeyState == 0) + NetWriteString2(pParams->Socket, (char *)PF12_KEY, strlen(PF12_KEY), 0); + else if (dwControlKeyState == SHIFT_PRESSED) + NetWriteString2(pParams->Socket, (char *)SHIFT_PF12_KEY, strlen(SHIFT_PF12_KEY), 0); + else if (dwControlKeyState == LEFT_CTRL_PRESSED || + dwControlKeyState == RIGHT_CTRL_PRESSED) + NetWriteString2(pParams->Socket, (char *)CTRL_PF12_KEY, strlen(CTRL_PF12_KEY), 0); + else if (dwControlKeyState == LEFT_ALT_PRESSED || + dwControlKeyState == RIGHT_ALT_PRESSED) + NetWriteString2(pParams->Socket, (char *)ALT_PF12_KEY, strlen(ALT_PF12_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED)) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_CTRL_PF12_KEY, strlen(SHIFT_ALT_CTRL_PF12_KEY), 0); + else if ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)ALT_CTRL_PF12_KEY, strlen(ALT_CTRL_PF12_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & RIGHT_ALT_PRESSED) || + (dwControlKeyState & LEFT_ALT_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_ALT_PF12_KEY, strlen(SHIFT_ALT_PF12_KEY), 0); + else if ((dwControlKeyState & SHIFT_PRESSED) && + ((dwControlKeyState & LEFT_CTRL_PRESSED) || + (dwControlKeyState & RIGHT_CTRL_PRESSED))) + NetWriteString2(pParams->Socket, (char *)SHIFT_CTRL_PF12_KEY, strlen(SHIFT_CTRL_PF12_KEY), 0); + break; + default: + { + NetWriteString2(pParams->Socket, (char *)octets, n, 0); + break; + } + } + } + } + break; + } + break; + } + + return glob_outlen ; +} + + diff --git a/contrib/win32/win32compat/tncon.h b/contrib/win32/win32compat/tncon.h new file mode 100644 index 000000000..c36c02b4b --- /dev/null +++ b/contrib/win32/win32compat/tncon.h @@ -0,0 +1,184 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* tncon.h + * + * Contains terminal emulation console related key definition + * + */ +#ifndef __TNCON_H +#define __TNCON_H + +#include "console.h" + +#define UP_ARROW "\x1b[A" +#define DOWN_ARROW "\x1b[B" +#define RIGHT_ARROW "\x1b[C" +#define LEFT_ARROW "\x1b[D" + +#define APP_UP_ARROW "\x1bOA" +#define APP_DOWN_ARROW "\x1bOB" +#define APP_RIGHT_ARROW "\x1bOC" +#define APP_LEFT_ARROW "\x1bOD" + +#define FIND_KEY "\x1b[1~" +#define INSERT_KEY "\x1b[2~" +#define REMOVE_KEY "\x1b[3~" +#define SELECT_KEY "\x1b[4~" +#define PREV_KEY "\x1b[5~" +#define NEXT_KEY "\x1b[6~" +#define SHIFT_TAB_KEY "\x1b[~" +#define ESCAPE_KEY "\x1b" +#define BACKSPACE_KEY "\b" + +// VT100 Function Key's +#define VT100_PF1_KEY "\x1bO2" +#define VT100_PF2_KEY "\x1bO3" +#define VT100_PF3_KEY "\x1bO4" +#define VT100_PF4_KEY "\x1bO5" +#define VT100_PF5_KEY "\x1bO6" +#define VT100_PF6_KEY "\x1bO7" +#define VT100_PF7_KEY "\x1bO8" +#define VT100_PF8_KEY "\x1bO9" +#define VT100_PF9_KEY "\x1bO:" +#define VT100_PF10_KEY "\x1bO;" + +// VT420 Key's +#define PF1_KEY "\x1b[11~" +#define PF2_KEY "\x1b[12~" +#define PF3_KEY "\x1b[13~" +#define PF4_KEY "\x1b[14~" +#define PF5_KEY "\x1b[15~" +#define PF6_KEY "\x1b[17~" +#define PF7_KEY "\x1b[18~" +#define PF8_KEY "\x1b[19~" +#define PF9_KEY "\x1b[20~" +#define PF10_KEY "\x1b[21~" +#define PF11_KEY "\x1b[23~" +#define PF12_KEY "\x1b[24~" + +#define SHIFT_PF1_KEY "\x1b[11;2~" +#define SHIFT_PF2_KEY "\x1b[12;2~" +#define SHIFT_PF3_KEY "\x1b[13;2~" +#define SHIFT_PF4_KEY "\x1b[14;2~" +#define SHIFT_PF5_KEY "\x1b[15;2~" +#define SHIFT_PF6_KEY "\x1b[17;2~" +#define SHIFT_PF7_KEY "\x1b[18;2~" +#define SHIFT_PF8_KEY "\x1b[19;2~" +#define SHIFT_PF9_KEY "\x1b[20;2~" +#define SHIFT_PF10_KEY "\x1b[21;2~" +#define SHIFT_PF11_KEY "\x1b[24;2~" +#define SHIFT_PF12_KEY "\x1b[25;2~" + +#define ALT_PF1_KEY "\x1b[11;3~" +#define ALT_PF2_KEY "\x1b[12;3~" +#define ALT_PF3_KEY "\x1b[13;3~" +#define ALT_PF4_KEY "\x1b[14;3~" +#define ALT_PF5_KEY "\x1b[15;3~" +#define ALT_PF6_KEY "\x1b[17;3~" +#define ALT_PF7_KEY "\x1b[18;3~" +#define ALT_PF8_KEY "\x1b[19;3~" +#define ALT_PF9_KEY "\x1b[20;3~" +#define ALT_PF10_KEY "\x1b[21;3~" +#define ALT_PF11_KEY "\x1b[24;3~" +#define ALT_PF12_KEY "\x1b[25;3~" + +#define CTRL_PF1_KEY "\x1b[11;4~" +#define CTRL_PF2_KEY "\x1b[12;4~" +#define CTRL_PF3_KEY "\x1b[13;4~" +#define CTRL_PF4_KEY "\x1b[14;4~" +#define CTRL_PF5_KEY "\x1b[15;4~" +#define CTRL_PF6_KEY "\x1b[17;4~" +#define CTRL_PF7_KEY "\x1b[18;4~" +#define CTRL_PF8_KEY "\x1b[19;4~" +#define CTRL_PF9_KEY "\x1b[20;4~" +#define CTRL_PF10_KEY "\x1b[21;4~" +#define CTRL_PF11_KEY "\x1b[24;4~" +#define CTRL_PF12_KEY "\x1b[25;4~" + +#define SHIFT_CTRL_PF1_KEY "\x1b[11;6~" +#define SHIFT_CTRL_PF2_KEY "\x1b[12;6~" +#define SHIFT_CTRL_PF3_KEY "\x1b[13;6~" +#define SHIFT_CTRL_PF4_KEY "\x1b[14;6~" +#define SHIFT_CTRL_PF5_KEY "\x1b[15;6~" +#define SHIFT_CTRL_PF6_KEY "\x1b[17;6~" +#define SHIFT_CTRL_PF7_KEY "\x1b[18;6~" +#define SHIFT_CTRL_PF8_KEY "\x1b[19;6~" +#define SHIFT_CTRL_PF9_KEY "\x1b[20;6~" +#define SHIFT_CTRL_PF10_KEY "\x1b[21;6~" +#define SHIFT_CTRL_PF11_KEY "\x1b[24;6~" +#define SHIFT_CTRL_PF12_KEY "\x1b[25;6~" + +#define SHIFT_ALT_PF1_KEY "\x1b[11;5~" +#define SHIFT_ALT_PF2_KEY "\x1b[12;5~" +#define SHIFT_ALT_PF3_KEY "\x1b[13;5~" +#define SHIFT_ALT_PF4_KEY "\x1b[14;5~" +#define SHIFT_ALT_PF5_KEY "\x1b[15;5~" +#define SHIFT_ALT_PF6_KEY "\x1b[17;5~" +#define SHIFT_ALT_PF7_KEY "\x1b[18;5~" +#define SHIFT_ALT_PF8_KEY "\x1b[19;5~" +#define SHIFT_ALT_PF9_KEY "\x1b[20;5~" +#define SHIFT_ALT_PF10_KEY "\x1b[21;5~" +#define SHIFT_ALT_PF11_KEY "\x1b[24;5~" +#define SHIFT_ALT_PF12_KEY "\x1b[25;5~" + +#define ALT_CTRL_PF1_KEY "\x1b[11;7~" +#define ALT_CTRL_PF2_KEY "\x1b[12;7~" +#define ALT_CTRL_PF3_KEY "\x1b[13;7~" +#define ALT_CTRL_PF4_KEY "\x1b[14;7~" +#define ALT_CTRL_PF5_KEY "\x1b[15;7~" +#define ALT_CTRL_PF6_KEY "\x1b[17;7~" +#define ALT_CTRL_PF7_KEY "\x1b[18;7~" +#define ALT_CTRL_PF8_KEY "\x1b[19;7~" +#define ALT_CTRL_PF9_KEY "\x1b[20;7~" +#define ALT_CTRL_PF10_KEY "\x1b[21;7~" +#define ALT_CTRL_PF11_KEY "\x1b[24;7~" +#define ALT_CTRL_PF12_KEY "\x1b[25;7~" + +#define SHIFT_ALT_CTRL_PF1_KEY "\x1b[11;8~" +#define SHIFT_ALT_CTRL_PF2_KEY "\x1b[12;8~" +#define SHIFT_ALT_CTRL_PF3_KEY "\x1b[13;8~" +#define SHIFT_ALT_CTRL_PF4_KEY "\x1b[14;8~" +#define SHIFT_ALT_CTRL_PF5_KEY "\x1b[15;8~" +#define SHIFT_ALT_CTRL_PF6_KEY "\x1b[17;8~" +#define SHIFT_ALT_CTRL_PF7_KEY "\x1b[18;8~" +#define SHIFT_ALT_CTRL_PF8_KEY "\x1b[19;8~" +#define SHIFT_ALT_CTRL_PF9_KEY "\x1b[20;8~" +#define SHIFT_ALT_CTRL_PF10_KEY "\x1b[21;8~" +#define SHIFT_ALT_CTRL_PF11_KEY "\x1b[24;8~" +#define SHIFT_ALT_CTRL_PF12_KEY "\x1b[25;8~" + +#define TERMINAL_ID "\x1b[?1;2c" +#define STATUS_REPORT "\x1b[2;5R" +#define CURSOR_REPORT_FORMAT_STRING "\x1b[%d;%dR" +#define VT52_TERMINAL_ID "\x1b/Z" + +int ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen); + +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/tnnet.c b/contrib/win32/win32compat/tnnet.c new file mode 100644 index 000000000..a5ee3e2e3 --- /dev/null +++ b/contrib/win32/win32compat/tnnet.c @@ -0,0 +1,94 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* tnnet.c + * + * Contains terminal emulation related network calls to invoke ANSI parsing engine + * + */ + +#include +#include +#include +#include +#include + +#include "ansiprsr.h" + +#define dwBuffer 4096 + +// Server will always be returning a sequence of ANSI control characters which the client +// protocol can either passthru directly to the console or transform based on an output terminal +// type. We're not using termcap so we're only supporting the ANSI (vt100) sequences that +// are hardcoded in the server and will be transformed to Windows Console commands. + +size_t telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resplen) +{ + unsigned char szBuffer[dwBuffer + 8]; + + unsigned char* pszNewHead = NULL; + + unsigned char* pszHead = NULL; + unsigned char* pszTail = NULL; + + char *term = NULL; + + if (len == 0) + return len; + + term = getenv("TERM"); + + if (term != NULL && _stricmp(term, "passthru") == 0) + return len; + + // Transform a single carriage return into a single linefeed before + // continuing. + if ((len == 1) && (buf[0] == 13)) + buf[0] = 10; + + pszTail = (unsigned char *)buf; + pszHead = (unsigned char *)buf; + + pszTail += len; + + pszNewHead = pszHead; + + // Loop through the network buffer transforming characters as necessary. + // The buffer will be empty after the transformation + // process since the buffer will contain only commands that are handled by the console API. + do { + pszHead = pszNewHead; + pszNewHead = ParseBuffer(pszHead, pszTail, respbuf, resplen); + + } while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && (resplen == NULL || (resplen != NULL && *resplen == 0))); + + len = 0; + + return len; +} diff --git a/contrib/win32/win32compat/tnnet.h b/contrib/win32/win32compat/tnnet.h new file mode 100644 index 000000000..d2fb54b67 --- /dev/null +++ b/contrib/win32/win32compat/tnnet.h @@ -0,0 +1,42 @@ +/* + * Author: Microsoft Corp. + * + * Copyright (c) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * 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. + */ +/* tnnet.h + * + * Contains terminal emulation related network calls to invoke ANSI parsing engine + * + */ + +#ifndef __TNNET_H +#define __TNNET_H + + size_t telProcessNetwork (char *buf, size_t len, unsigned char **respbuf, size_t *resplen); + +#endif + \ No newline at end of file diff --git a/contrib/win32/win32compat/ttymodes_windows.c b/contrib/win32/win32compat/ttymodes_windows.c new file mode 100644 index 000000000..6d8db1fd5 --- /dev/null +++ b/contrib/win32/win32compat/ttymodes_windows.c @@ -0,0 +1,230 @@ +/* + * SSH2 tty modes for Windows + * + * 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 "includes.h" + +#include + +#include +#include +#include +#include + +#include "packet.h" +#include "log.h" +#include "compat.h" +#include "buffer.h" + +#define TTY_OP_END 0 +/* + * uint32 (u_int) follows speed in SSH1 and SSH2 + */ +#define TTY_OP_ISPEED_PROTO1 192 +#define TTY_OP_OSPEED_PROTO1 193 +#define TTY_OP_ISPEED_PROTO2 128 +#define TTY_OP_OSPEED_PROTO2 129 + +/* + * Encodes terminal modes for the terminal referenced by fd + * or tiop in a portable manner, and appends the modes to a packet + * being constructed. + */ +void +tty_make_modes(int fd, struct termios *tiop) +{ + int baud; + Buffer buf; + int tty_op_ospeed, tty_op_ispeed; + void (*put_arg)(Buffer *, u_int); + + buffer_init(&buf); + if (compat20) { + tty_op_ospeed = TTY_OP_OSPEED_PROTO2; + tty_op_ispeed = TTY_OP_ISPEED_PROTO2; + put_arg = buffer_put_int; + } else { + tty_op_ospeed = TTY_OP_OSPEED_PROTO1; + tty_op_ispeed = TTY_OP_ISPEED_PROTO1; + put_arg = (void (*)(Buffer *, u_int)) buffer_put_char; + } + + /* Store input and output baud rates. */ + baud = 9600; + + buffer_put_char(&buf, tty_op_ospeed); + buffer_put_int(&buf, baud); + baud = 9600; + buffer_put_char(&buf, tty_op_ispeed); + buffer_put_int(&buf, baud); + + /* Store values of mode flags. */ +#define TTYCHAR(NAME, OP) \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, special_char_encode(tio.c_cc[NAME])); + +#define TTYMODE(NAME, FIELD, OP) \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, ((tio.FIELD & NAME) != 0)); + +#undef TTYCHAR +#undef TTYMODE + +end: + /* Mark end of mode data. */ + buffer_put_char(&buf, TTY_OP_END); + if (compat20) + packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); + else + packet_put_raw(buffer_ptr(&buf), buffer_len(&buf)); + buffer_free(&buf); +} + +/* + * Decodes terminal modes for the terminal referenced by fd in a portable + * manner from a packet being read. + */ +void +tty_parse_modes(int fd, int *n_bytes_ptr) +{ + + u_int tio[255]; // win32 dummy + u_int tioFIELD ; + int opcode, baud; + int n_bytes = 0; + int failure = 0; + u_int (*get_arg)(void); + int arg_size; + + if (compat20) { + *n_bytes_ptr = packet_get_int(); + if (*n_bytes_ptr == 0) + return; + get_arg = packet_get_int; + arg_size = 4; + } else { + get_arg = packet_get_char; + arg_size = 1; + } + + for (;;) { + n_bytes += 1; + opcode = packet_get_char(); + switch (opcode) { + case TTY_OP_END: + goto set; + + /* XXX: future conflict possible */ + case TTY_OP_ISPEED_PROTO1: + case TTY_OP_ISPEED_PROTO2: + n_bytes += 4; + baud = packet_get_int(); + break; + + /* XXX: future conflict possible */ + case TTY_OP_OSPEED_PROTO1: + case TTY_OP_OSPEED_PROTO2: + n_bytes += 4; + baud = packet_get_int(); + break; + +#define TTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += arg_size; \ + tio[NAME] = special_char_decode(get_arg()); \ + break; +#define TTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += arg_size; \ + if (get_arg()) \ + tioFIELD |= NAME; \ + else \ + tioFIELD &= ~NAME; \ + break; + +#undef TTYCHAR +#undef TTYMODE + + default: + debug("Ignoring unsupported tty mode opcode %d (0x%x)", + opcode, opcode); + if (!compat20) { + /* + * SSH1: + * Opcodes 1 to 127 are defined to have + * a one-byte argument. + * Opcodes 128 to 159 are defined to have + * an integer argument. + */ + if (opcode > 0 && opcode < 128) { + n_bytes += 1; + (void) packet_get_char(); + break; + } else if (opcode >= 128 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + /* + * It is a truly undefined opcode (160 to 255). + * We have no idea about its arguments. So we + * must stop parsing. Note that some data + * may be left in the packet; hopefully there + * is nothing more coming after the mode data. + */ + logit("parse_tty_modes: unknown opcode %d", + opcode); + goto set; + } + } else { + /* + * SSH2: + * Opcodes 1 to 159 are defined to have + * a uint32 argument. + * Opcodes 160 to 255 are undefined and + * cause parsing to stop. + */ + if (opcode > 0 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + logit("parse_tty_modes: unknown opcode %d", + opcode); + goto set; + } + } + } + } + +set: + if (*n_bytes_ptr != n_bytes) { + *n_bytes_ptr = n_bytes; + logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", + *n_bytes_ptr, n_bytes); + return; /* Don't process bytes passed */ + } + if (failure == -1) + return; /* Packet parsed ok but tcgetattr() failed */ + +} diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c new file mode 100644 index 000000000..9353f8cc2 --- /dev/null +++ b/contrib/win32/win32compat/w32fd.c @@ -0,0 +1,851 @@ +/* +* Author: Manoj Ampalam +* +* Implementation of POSIX APIs +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 "inc\w32posix.h" +#include "w32fd.h" +#include "signal_internal.h" +#include +#include +#include +#include +#include +#include +#include "Shlwapi.h" +#include + +/* internal table that stores the fd to w32_io mapping*/ +struct w32fd_table { + w32_fd_set occupied; /*bit map for tracking occipied table entries*/ + struct w32_io* w32_ios[MAX_FDS];/*array of references to mapped w32_io objects*/ +}; + +/* mapping table*/ +static struct w32fd_table fd_table; + +/* static table entries representing std in, out and error*/ +static struct w32_io w32_io_stdin, w32_io_stdout, w32_io_stderr; + +/* main thread handle*/ +HANDLE main_thread; + +void fd_table_set(struct w32_io* pio, int index); + +/* initializes mapping table*/ +static int +fd_table_initialize() { + memset(&fd_table, 0, sizeof(fd_table)); + memset(&w32_io_stdin, 0, sizeof(w32_io_stdin)); + w32_io_stdin.std_handle = STD_INPUT_HANDLE; + w32_io_stdin.type = STD_IO_FD; + fd_table_set(&w32_io_stdin, STDIN_FILENO); + memset(&w32_io_stdout, 0, sizeof(w32_io_stdout)); + w32_io_stdout.std_handle = STD_OUTPUT_HANDLE; + w32_io_stdout.type = STD_IO_FD; + fd_table_set(&w32_io_stdout, STDOUT_FILENO); + memset(&w32_io_stderr, 0, sizeof(w32_io_stderr)); + w32_io_stderr.std_handle = STD_ERROR_HANDLE; + w32_io_stderr.type = STD_IO_FD; + fd_table_set(&w32_io_stderr, STDERR_FILENO); + return 0; +} + +/* get a free slot in mapping table with least index*/ +static int +fd_table_get_min_index() { + int min_index = 0; + unsigned char* bitmap = fd_table.occupied.bitmap; + unsigned char tmp; + + while (*bitmap == 0xff) { + bitmap++; + min_index += 8; + if (min_index >= MAX_FDS) { + errno = EMFILE; + debug("ERROR: MAX_FDS limit reached"); + return -1; + } + } + + tmp = *bitmap; + + while (tmp & 0x80) + { + tmp <<= 1; + min_index++; + } + + return min_index; +} + +/* maps pio to fd (specified by index)*/ +static void +fd_table_set(struct w32_io* pio, int index) { + fd_table.w32_ios[index] = pio; + pio->table_index = index; + assert(pio->type != UNKNOWN_FD); + FD_SET(index, &(fd_table.occupied)); +} + +/* removes entry at index from mapping table*/ +static void +fd_table_clear(int index) +{ + fd_table.w32_ios[index]->table_index = -1; + fd_table.w32_ios[index] = NULL; + FD_CLR(index, &(fd_table.occupied)); +} + +void +w32posix_initialize() { + if ((fd_table_initialize() != 0) + || (socketio_initialize() != 0)) + DebugBreak(); + main_thread = OpenThread(THREAD_SET_CONTEXT | SYNCHRONIZE, FALSE, GetCurrentThreadId()); + if ((main_thread == NULL) || (sw_initialize() != 0) || w32_programdir() == NULL) { + DebugBreak(); + fatal("failed to initialize w32posix wrapper"); + } +} + +void +w32posix_done() { + socketio_done(); +} + +/* Check if the corresponding fd is set blocking */ +BOOL +w32_io_is_blocking(struct w32_io* pio) +{ + return (pio->fd_status_flags & O_NONBLOCK) ? FALSE : TRUE; +} + +/* +* Check if io is ready/available. This function is primarily used by select() +* as it decides on what fds can be set. +*/ +BOOL +w32_io_is_io_available(struct w32_io* pio, BOOL rd) { + if (pio->type == SOCK_FD) + return socketio_is_io_available(pio, rd); + else + return fileio_is_io_available(pio, rd); +} + +void +w32_io_on_select(struct w32_io* pio, BOOL rd) +{ + if ((pio->type == SOCK_FD)) + socketio_on_select(pio, rd); + else + fileio_on_select(pio, rd); +} + +#define CHECK_FD(fd) do { \ + debug3("%s fd:%d", __FUNCTION__, fd); \ + errno = 0; \ + if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { \ + errno = EBADF; \ + debug("%s ERROR: bad fd: %d", __FUNCTION__, fd); \ + return -1; \ + } \ +} while (0) + +#define CHECK_SOCK_IO(pio) do { \ + errno = 0; \ + if (pio->type != SOCK_FD) { \ + errno = ENOTSOCK; \ + debug("%s ERROR: not sock :%d", __FUNCTION__, pio->type); \ + return -1; \ + } \ +} while (0) + +int +w32_socket(int domain, 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 = socketio_socket(domain, type, protocol); + if (pio == NULL) + return -1; + + pio->type = SOCK_FD; + fd_table_set(pio, min_index); + debug("socket:%d, io:%p, fd:%d ", pio->sock, pio, min_index); + return min_index; +} + +int +w32_accept(int fd, struct sockaddr* addr, int* addrlen) +{ + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + int min_index = fd_table_get_min_index(); + struct w32_io* pio = NULL; + + if (min_index == -1) + return -1; + + pio = socketio_accept(fd_table.w32_ios[fd], addr, addrlen); + if (!pio) + return -1; + + pio->type = SOCK_FD; + fd_table_set(pio, min_index); + debug("socket:%d, io:%p, fd:%d ", pio->sock, pio, min_index); + return min_index; +} + +int +w32_setsockopt(int fd, int level, int optname, const void* optval, int optlen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_setsockopt(fd_table.w32_ios[fd], level, optname, (const char*)optval, optlen); +} + +int +w32_getsockopt(int fd, int level, int optname, void* optval, int* optlen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_getsockopt(fd_table.w32_ios[fd], level, optname, (char*)optval, optlen); +} + +int +w32_getsockname(int fd, struct sockaddr* name, int* namelen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_getsockname(fd_table.w32_ios[fd], name, namelen); +} + +int +w32_getpeername(int fd, struct sockaddr* name, int* namelen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_getpeername(fd_table.w32_ios[fd], name, namelen); +} + +int +w32_listen(int fd, int backlog) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_listen(fd_table.w32_ios[fd], backlog); +} + +int +w32_bind(int fd, const struct sockaddr *name, int namelen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_bind(fd_table.w32_ios[fd], name, namelen); +} + +int +w32_connect(int fd, const struct sockaddr* name, int namelen) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_connect(fd_table.w32_ios[fd], name, namelen); +} + +int +w32_recv(int fd, void *buf, size_t len, int flags) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_recv(fd_table.w32_ios[fd], buf, len, flags); +} + +int +w32_send(int fd, const void *buf, size_t len, int flags) { + + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_send(fd_table.w32_ios[fd], buf, len, flags); +} + + +int +w32_shutdown(int fd, int how) { + debug2("shutdown - fd:%d how:%d", fd, how); + CHECK_FD(fd); + CHECK_SOCK_IO(fd_table.w32_ios[fd]); + return socketio_shutdown(fd_table.w32_ios[fd], how); +} + +int +w32_socketpair(int domain, int type, int protocol, int sv[2]) { + errno = ENOTSUP; + debug("socketpair - ERROR not supported"); + return -1; +} + + +int +w32_pipe(int *pfds) { + int read_index, write_index; + struct w32_io* pio[2]; + + errno = 0; + read_index = fd_table_get_min_index(); + if (read_index == -1) + return -1; + + /*temporarily set occupied bit*/ + FD_SET(read_index, &fd_table.occupied); + write_index = fd_table_get_min_index(); + FD_CLR(read_index, &fd_table.occupied); + if (write_index == -1) + return -1; + + if (-1 == fileio_pipe(pio)) + return -1; + + pio[0]->type = NONSOCK_FD; + pio[1]->type = NONSOCK_FD; + fd_table_set(pio[0], read_index); + fd_table_set(pio[1], write_index); + pfds[0] = read_index; + pfds[1] = write_index; + debug("pipe - r-h:%d,io:%p,fd:%d w-h:%d,io:%p,fd:%d", + pio[0]->handle, pio[0], read_index, pio[1]->handle, pio[1], write_index); + return 0; +} +char *realpath_win(const char *path, char resolved[MAX_PATH]); +int +w32_open(const char *pathname, int flags, ...) { + int min_index = fd_table_get_min_index(); + struct w32_io* pio; + + errno = 0; + if (min_index == -1) + return -1; + + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(pathname, resolvedPathName); + + pio = fileio_open(resolvedPathName, flags, 0); + if (pio == NULL) + return -1; + + pio->type = NONSOCK_FD; + fd_table_set(pio, min_index); + debug("open - handle:%p, io:%p, fd:%d", pio->handle, pio, min_index); + debug3("open - path:%s", resolvedPathName); + return min_index; +} + +int +w32_read(int fd, void *dst, size_t max) { + CHECK_FD(fd); + + if (fd_table.w32_ios[fd]->type == SOCK_FD) + return socketio_recv(fd_table.w32_ios[fd], dst, max, 0); + + return fileio_read(fd_table.w32_ios[fd], dst, max); +} + +int +w32_write(int fd, const void *buf, unsigned int max) { + CHECK_FD(fd); + + if (fd_table.w32_ios[fd]->type == SOCK_FD) + return socketio_send(fd_table.w32_ios[fd], buf, max, 0); + + return fileio_write(fd_table.w32_ios[fd], buf, max); +} + +int w32_writev(int fd, const struct iovec *iov, int iovcnt) { + int written = 0; + int i = 0; + + CHECK_FD(fd); + + for (i = 0; i < iovcnt; i++) { + int ret = w32_write(fd, iov[i].iov_base, iov[i].iov_len); + + if (ret > 0) { + written += ret; + } + } + + return written; +} + +int +w32_fstat(int fd, struct w32_stat *buf) { + CHECK_FD(fd); + return fileio_fstat(fd_table.w32_ios[fd], (struct _stat64*)buf); +} + +long +w32_lseek(int fd, long offset, int origin) { + CHECK_FD(fd); + return fileio_lseek(fd_table.w32_ios[fd], offset, origin); +} + +int +w32_isatty(int fd) { + struct w32_io* pio; + if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { + errno = EBADF; + return 0; + } + + pio = fd_table.w32_ios[fd]; + + if (FILETYPE(pio) == FILE_TYPE_CHAR) + return 1; + else { + errno = EINVAL; + return 0; + } +} + +FILE* +w32_fdopen(int fd, const char *mode) { + errno = 0; + if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { + errno = EBADF; + debug("fdopen - ERROR bad fd: %d", fd); + return NULL; + } + return fileio_fdopen(fd_table.w32_ios[fd], mode); +} + +int +w32_close(int fd) { + struct w32_io* pio; + + if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { + errno = EBADF; + return -1; + } + + pio = fd_table.w32_ios[fd]; + + debug("close - io:%p, type:%d, fd:%d, table_index:%d", pio, pio->type, fd, + pio->table_index); + fd_table_clear(pio->table_index); + + if (pio->type == SOCK_FD) + return socketio_close(pio); + else + switch (FILETYPE(pio)) { + case FILE_TYPE_CHAR: + return termio_close(pio); + default: + return fileio_close(pio); + } +} + +static int +w32_io_process_fd_flags(struct w32_io* pio, int flags) { + DWORD shi_flags; + if (flags & ~FD_CLOEXEC) { + debug("fcntl - ERROR unsupported flags %d, io:%p", flags, pio); + errno = ENOTSUP; + return -1; + } + + shi_flags = (flags & FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT; + + if (SetHandleInformation(WINHANDLE(pio), HANDLE_FLAG_INHERIT, shi_flags) == FALSE) { + debug("fcntl - SetHandleInformation failed %d, io:%p", + GetLastError(), pio); + errno = EOTHER; + return -1; + } + + pio->fd_flags = flags; + return 0; +} + +int +w32_fcntl(int fd, int cmd, ... /* arg */) { + va_list valist; + va_start(valist, cmd); + int ret = 0; + + CHECK_FD(fd); + + switch (cmd) { + case F_GETFL: + ret = fd_table.w32_ios[fd]->fd_status_flags; + break; + case F_SETFL: + fd_table.w32_ios[fd]->fd_status_flags = va_arg(valist, int); + ret = 0; + break; + case F_GETFD: + ret = fd_table.w32_ios[fd]->fd_flags; + break; + case F_SETFD: + ret = w32_io_process_fd_flags(fd_table.w32_ios[fd], va_arg(valist, int)); + break; + default: + errno = EINVAL; + debug("fcntl - ERROR not supported cmd:%d", cmd); + ret = -1; + break; + } + + va_end(valist); + return ret; +} + +#define SELECT_EVENT_LIMIT 32 +int +w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* exceptfds, + const struct timeval *timeout) { + ULONGLONG ticks_start = GetTickCount64(), ticks_spent; + w32_fd_set read_ready_fds, write_ready_fds; + HANDLE events[SELECT_EVENT_LIMIT]; + int num_events = 0; + int in_set_fds = 0, out_ready_fds = 0, i; + unsigned int timeout_ms = 0, time_rem = 0; + + errno = 0; + /* TODO - the size of these can be reduced based on fds */ + memset(&read_ready_fds, 0, sizeof(w32_fd_set)); + memset(&write_ready_fds, 0, sizeof(w32_fd_set)); + + if (timeout) + timeout_ms = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + + if (fds > MAX_FDS) { + errno = EINVAL; + debug("select - ERROR: invalid fds: %d", fds); + return -1; + } + + if (!readfds && !writefds) { + errno = EINVAL; + debug("select - ERROR: null fd_sets"); + return -1; + } + + /* TODO - see if this needs to be supported */ + //if (exceptfds) { + // errno = EOPNOTSUPP; + // debug("select - ERROR: exceptfds not supported"); + // DebugBreak(); + // return -1; + //} + + if (readfds) { + for (i = 0; i < fds; i++) + if (FD_ISSET(i, readfds)) { + CHECK_FD(i); + in_set_fds++; + } + } + + if (writefds) { + for (i = 0; i < fds; i++) + if (FD_ISSET(i, writefds)) { + CHECK_FD(i); + in_set_fds++; + } + } + + /* if none of input fds are set return error */ + if (in_set_fds == 0) { + errno = EINVAL; + debug("select - ERROR: empty fd_sets"); + return -1; + } + + debug3("Total in fds:%d", in_set_fds); + /* + * start async io on selected fds if needed and pick up any events + * that select needs to listen on + */ + for (int i = 0; i < fds; i++) { + + if (readfds && FD_ISSET(i, readfds)) { + w32_io_on_select(fd_table.w32_ios[i], TRUE); + if ((fd_table.w32_ios[i]->type == SOCK_FD) + && (fd_table.w32_ios[i]->internal.state == SOCK_LISTENING)) { + if (num_events == SELECT_EVENT_LIMIT) { + debug("select - ERROR: max #events breach"); + errno = ENOMEM; + return -1; + } + events[num_events++] = fd_table.w32_ios[i]->read_overlapped.hEvent; + } + } + + if (writefds && FD_ISSET(i, writefds)) { + w32_io_on_select(fd_table.w32_ios[i], FALSE); + if ((fd_table.w32_ios[i]->type == SOCK_FD) + && (fd_table.w32_ios[i]->internal.state == SOCK_CONNECTING)) { + if (num_events == SELECT_EVENT_LIMIT) { + debug("select - ERROR: max #events reached for select"); + errno = ENOMEM; + return -1; + } + events[num_events++] = fd_table.w32_ios[i]->write_overlapped.hEvent; + } + } + } + + /* excute any scheduled APCs */ + if (0 != wait_for_any_event(NULL, 0, 0)) + return -1; + + /* see if any io is ready */ + for (i = 0; i < fds; i++) { + + if (readfds && FD_ISSET(i, readfds)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], TRUE)) { + FD_SET(i, &read_ready_fds); + out_ready_fds++; + } + } + + if (writefds && FD_ISSET(i, writefds)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) { + FD_SET(i, &write_ready_fds); + out_ready_fds++; + } + } + } + + + /* timeout specified and both fields are 0 - polling mode*/ + /* proceed with further wait if not in polling mode*/ + if ((timeout == NULL) || (timeout_ms != 0)) + /* wait for io until any is ready */ + while (out_ready_fds == 0) { + ticks_spent = GetTickCount64() - ticks_start; + time_rem = 0; + + if (timeout != NULL) { + if (timeout_ms < ticks_spent) { + debug("select - timing out"); + break; + } + time_rem = timeout_ms - (ticks_spent & 0xffffffff); + } + else + time_rem = INFINITE; + + if (0 != wait_for_any_event(events, num_events, time_rem)) + return -1; + + /* check on fd status */ + out_ready_fds = 0; + for (int i = 0; i < fds; i++) { + + if (readfds && FD_ISSET(i, readfds)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], TRUE)) { + FD_SET(i, &read_ready_fds); + out_ready_fds++; + } + } + + if (writefds && FD_ISSET(i, writefds)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) { + FD_SET(i, &write_ready_fds); + out_ready_fds++; + } + } + } + + if (out_ready_fds == 0) + debug3("select - wait ended without any IO completion, looping again"); + + } + + /* clear out fds that are not ready yet */ + if (readfds) + for (i = 0; i < fds; i++) + if (FD_ISSET(i, readfds) && (!FD_ISSET(i, &read_ready_fds))) + FD_CLR(i, readfds); + + if (writefds) + for (i = 0; i < fds; i++) + if (FD_ISSET(i, writefds)) { + if (FD_ISSET(i, &write_ready_fds)) { + /* for connect() completed sockets finish WSA connect process*/ + if ((fd_table.w32_ios[i]->type == SOCK_FD) + && ((fd_table.w32_ios[i]->internal.state == SOCK_CONNECTING))) + if (socketio_finish_connect(fd_table.w32_ios[i]) != 0) { + /* finalizeing connect failed - recored error */ + /* error gets picked up later recv and/or send*/ + fd_table.w32_ios[i]->read_details.error = errno; + fd_table.w32_ios[i]->write_details.error = errno; + fd_table.w32_ios[i]->internal.state = SOCK_CONNECTED; + errno = 0; + } + } + else + FD_CLR(i, writefds); + } + + debug3("select - returning %d", out_ready_fds); + return out_ready_fds; + +} + +int +w32_dup(int oldfd) { + int min_index; + struct w32_io* pio; + HANDLE src, target; + CHECK_FD(oldfd); + if (oldfd > STDERR_FILENO) { + errno = EOPNOTSUPP; + debug("dup - ERROR: supports only std io, fd:%d", oldfd); + return -1; + } + + if ((min_index = fd_table_get_min_index()) == -1) + return -1; + + src = GetStdHandle(fd_table.w32_ios[oldfd]->std_handle); + if (src == INVALID_HANDLE_VALUE) { + errno = EINVAL; + debug("dup - ERROR: unable to get underlying handle for std fd:%d", oldfd); + return -1; + } + + if (!DuplicateHandle(GetCurrentProcess(), src, GetCurrentProcess(), &target, 0, TRUE, DUPLICATE_SAME_ACCESS)) { + errno = EOTHER; + debug("dup - ERROR: DuplicatedHandle() :%d", GetLastError()); + return -1; + } + + pio = (struct w32_io*) malloc(sizeof(struct w32_io)); + if (pio == NULL) { + CloseHandle(target); + errno = ENOMEM; + debug("dup - ERROR: %d", errno); + return -1; + } + + memset(pio, 0, sizeof(struct w32_io)); + pio->handle = target; + pio->type = NONSOCK_FD; + fd_table_set(pio, min_index); + return min_index; +} + +int +w32_dup2(int oldfd, int newfd) { + CHECK_FD(oldfd); + errno = EOPNOTSUPP; + debug("dup2 - ERROR: not implemented yet"); + return -1; +} + +HANDLE +w32_fd_to_handle(int fd) { + HANDLE h = fd_table.w32_ios[fd]->handle; + if (fd <= STDERR_FILENO) + h = GetStdHandle(fd_table.w32_ios[fd]->std_handle); + return h; +} + +int w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock) { + int min_index = fd_table_get_min_index(); + struct w32_io* pio; + + if (min_index == -1) { + return -1; + } + + pio = malloc(sizeof(struct w32_io)); + if (pio == NULL) { + errno = ENOMEM; + return -1; + } + memset(pio, 0, sizeof(struct w32_io)); + + pio->type = is_sock? SOCK_FD : NONSOCK_FD; + pio->handle = h; + fd_table_set(pio, min_index); + return min_index; +} + + +unsigned int +w32_alarm(unsigned int seconds) { + return sw_alarm(seconds);; +} +sighandler_t +w32_signal(int signum, sighandler_t handler) { + return sw_signal(signum, handler); +} + +int +w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { + return sw_sigprocmask(how, set, oldset); +} + +int +w32_raise(int sig) { + return sw_raise(sig); +} + +int +w32_kill(int pid, int sig) { + return sw_kill(pid, sig); +} + +int +w32_ftruncate(int fd, off_t length) { + CHECK_FD(fd); + + if (!SetFilePointer(w32_fd_to_handle(fd), length, 0, FILE_BEGIN)) + return -1; + if (!SetEndOfFile(w32_fd_to_handle(fd))) + return -1; + + return 0; +} + +int +w32_fsync(int fd) { + CHECK_FD(fd); + + return FlushFileBuffers(w32_fd_to_handle(fd)); +} diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h new file mode 100644 index 000000000..0cb3a3453 --- /dev/null +++ b/contrib/win32/win32compat/w32fd.h @@ -0,0 +1,161 @@ +/* + * Author: Manoj Ampalam + * + * Definitions for Win32 wrapper functions with POSIX like signatures +*/ + +#pragma once + +#include +#include +#include "inc\defs.h" + +enum w32_io_type { + UNKNOWN_FD = 0, + SOCK_FD = 1, /*maps a socket fd*/ + NONSOCK_FD = 2, /*maps a file fd, pipe fd or a tty fd*/ + STD_IO_FD = 5 /*maps a std fd - ex. STDIN_FILE*/ +}; + +enum w32_io_sock_state { + SOCK_INITIALIZED = 0, + SOCK_LISTENING = 1, /*listen called on socket*/ + SOCK_ACCEPTED = 2, /*socket returned from accept()*/ + SOCK_CONNECTING = 3, /*connect called on socket, connect is in progress*/ + SOCK_CONNECTED = 4 /*connect completed on socket*/ +}; + +/* +* This structure encapsulates the state info needed to map a File Descriptor +* to Win32 Handle +*/ +struct w32_io { + OVERLAPPED read_overlapped; + OVERLAPPED write_overlapped; + struct { + /*internal read buffer*/ + char *buf; + DWORD buf_size; + /*bytes in internal buffer remaining to be read by application*/ + DWORD remaining; + /*bytes in internal buffer already read by application*/ + DWORD completed; + BOOL pending; /*waiting on a read operation to complete*/ + DWORD error; /*error reported on async read or accept completion*/ + }read_details; + struct { + /*internal write buffer*/ + char *buf; + DWORD buf_size; + /*bytes in internal buffer remaining to be written to network*/ + DWORD remaining; + /*bytes in internal buffer already written to network*/ + DWORD completed; + BOOL pending; /*waiting on a write operation to complete*/ + DWORD error; /*error reported on async write or connect completion*/ + }write_details; + + /*index at which this object is stored in fd_table*/ + int table_index; + enum w32_io_type type; /*hanldle type*/ + DWORD fd_flags; /*fd flags from POSIX*/ + DWORD fd_status_flags; /*fd status flags from POSIX*/ + + /*underlying w32 handle*/ + union { + SOCKET sock; + HANDLE handle; + DWORD std_handle; /* ex. STD_INPUT_HANDLE */ + }; + + /*handle specific internal state context, used by sockets and pipes*/ + struct { + enum w32_io_sock_state state; + void* context; + }internal; +}; + +#define WINHANDLE(pio) (((pio)->type == STD_IO_FD)? GetStdHandle((pio)->std_handle):(pio)->handle) +#define FILETYPE(pio) (GetFileType(WINHANDLE(pio))) +extern HANDLE main_thread; + +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); + +/*POSIX mimic'ing socket API*/ +int socketio_initialize(); +int socketio_done(); +BOOL socketio_is_io_available(struct w32_io* pio, BOOL rd); +void socketio_on_select(struct w32_io* pio, BOOL rd); +struct w32_io* socketio_socket(int domain, int type, int protocol); +struct w32_io* socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen); +int socketio_setsockopt(struct w32_io* pio, int level, int optname, + const char* optval, int optlen); +int socketio_getsockopt(struct w32_io* pio, int level, int optname, + char* optval, int* optlen); +int socketio_getsockname(struct w32_io* pio, struct sockaddr* name, int* namelen); +int socketio_getpeername(struct w32_io* pio, struct sockaddr* name, int* namelen); +int socketio_listen(struct w32_io* pio, int backlog); +int socketio_bind(struct w32_io* pio, const struct sockaddr *name, int namelen); +int socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen); +int socketio_finish_connect(struct w32_io* pio); +int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags); +int socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags); +int socketio_shutdown(struct w32_io* pio, int how); +int socketio_close(struct w32_io* pio); + +/*POSIX mimic'ing file API*/ +BOOL fileio_is_io_available(struct w32_io* pio, BOOL rd); +void fileio_on_select(struct w32_io* pio, BOOL rd); +int fileio_close(struct w32_io* pio); +int fileio_pipe(struct w32_io* pio[2]); +struct w32_io* fileio_open(const char *pathname, int flags, int mode); +int fileio_read(struct w32_io* pio, void *dst, unsigned int max); +int fileio_write(struct w32_io* pio, const void *buf, unsigned int max); +int fileio_fstat(struct w32_io* pio, struct _stat64 *buf); +int fileio_stat(const char *path, struct _stat64 *buf); +long fileio_lseek(struct w32_io* pio, long offset, int origin); +FILE* fileio_fdopen(struct w32_io* pio, const char *mode); + +/* terminal io specific versions */ +int termio_close(struct w32_io* pio); + +/* +* open() flags and modes +* all commented out macros are defined in fcntl.h +* they are listed here so as to cross check any conflicts with macros explicitly +* defined below. +*/ +/*open access modes. only one of these can be specified*/ +/* #define O_RDONLY 0x0 */ +/* #define O_WRONLY 0x1 */ +/* #define O_RDWR 0x2 */ +/* open file creation and file status flags can be bitwise-or'd*/ +/* #define O_APPEND 0x8 /*file is opened in append mode*/ +#ifndef O_NONBLOCK +#define O_NONBLOCK 0x0004 /*io operations wont block*/ +#endif +/* #define O_CREAT 0x100 /*If the file does not exist it will be created*/ +/* +* If the file exists and is a regular file, and the file is successfully +* opened O_RDWR or O_WRONLY, its length shall be truncated to 0, and the mode +* and owner shall be unchanged +*/ +/* #define O_TRUNC 0x200 */ +/* If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ +/* #define O_EXCL 0x400 */ +/* #define O_BINARY 0x8000 //Gives raw data (while O_TEXT normalises line endings */ +// open modes +#ifndef S_IRUSR +#define S_IRUSR 00400 //user has read permission +#endif // ! S_IRUSR +#ifndef S_IWUSR +#define S_IWUSR 00200 //user has write permission +#endif +#ifndef S_IRGRP +#define S_IRGRP 00040 //group has read permission +#endif +#ifndef S_IROTH +#define S_IROTH 00004 //others have read permission +#endif \ No newline at end of file diff --git a/contrib/win32/win32compat/w32log.c b/contrib/win32/win32compat/w32log.c new file mode 100644 index 000000000..06f2f4b41 --- /dev/null +++ b/contrib/win32/win32compat/w32log.c @@ -0,0 +1,56 @@ + +#include +#include +#include +#include +#include "inc\syslog.h" + +#define MSGBUFSIZ 1024 +static int logfd = -1; + +void openlog(char *ident, unsigned int option, int facility) { + if ((logfd == -1) && (ident != NULL)) { + wchar_t path[MAX_PATH], log_file[MAX_PATH + 12]; + if (GetModuleFileNameW(NULL, path, MAX_PATH) == 0) + return; + path[MAX_PATH - 1] = '\0'; + /* split path root and module */ + { + wchar_t* tail = path + wcslen(path), *p; + while (tail > path && *tail != L'\\' && *tail != L'/') + tail--; + + memcpy(log_file, path, (tail - path) * sizeof(wchar_t)); + p = log_file + (tail - path); + memcpy(p, L"\\logs\\", 12); + p += 6; + memcpy(p, tail + 1, (wcslen(tail + 1) - 3) * sizeof(wchar_t)); + p += wcslen(tail + 1) - 3; + memcpy(p, L"log\0", 8); + } + logfd = _wopen(log_file, O_WRONLY | O_CREAT | O_APPEND, + S_IREAD | S_IWRITE); + if (logfd != -1) + SetHandleInformation((HANDLE)_get_osfhandle(logfd), + HANDLE_FLAG_INHERIT, 0); + } +} + +void closelog(void) { + //NOOP +} + +void +syslog(int priority, const char *format, const char *formatBuffer) { + char msgbufTimestamp[MSGBUFSIZ]; + SYSTEMTIME st; + + if (logfd == -1) + return; + + GetLocalTime(&st); + snprintf(msgbufTimestamp, sizeof msgbufTimestamp, "%d %02d:%02d:%02d %03d %s\n", + GetCurrentProcessId(), st.wHour, st.wMinute, st.wSecond, + st.wMilliseconds, formatBuffer); + _write(logfd, msgbufTimestamp, strlen(msgbufTimestamp)); +} \ No newline at end of file diff --git a/contrib/win32/win32compat/win32_dirent.c b/contrib/win32/win32compat/win32_dirent.c new file mode 100644 index 000000000..e00937533 --- /dev/null +++ b/contrib/win32/win32compat/win32_dirent.c @@ -0,0 +1,131 @@ +// win32_dirent.c +// directory entry functions in Windows platform like Ubix/Linux +// opendir(), readdir(), closedir(). + +#include +#include +#include +#include +#include +#include "inc\utf.h" + +#include "inc\dirent.h" +#include "inc\libgen.h" + + +struct DIR_ { + intptr_t hFile; + struct _wfinddata_t c_file; + int first; +}; + +char * realpath_win(const char *path, char resolved[MAX_PATH]); + +/* Open a directory stream on NAME. + Return a DIR stream on the directory, or NULL if it could not be opened. */ +DIR * opendir(const char *name) +{ + struct _wfinddata_t c_file; + intptr_t hFile; + DIR *pdir; + wchar_t searchstr[MAX_PATH]; + wchar_t* wname = NULL; + int needed; + + // Skip the first '/' in the pathname + char resolvedPathName[MAX_PATH]; + realpath_win(name, resolvedPathName); + + if ((wname = utf8_to_utf16(resolvedPathName)) == NULL) { + errno = ENOMEM; + return NULL; + } + + // add *.* for Windows _findfirst() search pattern + swprintf_s(searchstr, MAX_PATH, L"%s\\*.*", wname); + free(wname); + + if ((hFile = _wfindfirst(searchstr, &c_file)) == -1L) + return NULL; /* errno is set by _wfindfirst */ + else { + if ((pdir = malloc(sizeof(DIR))) == NULL) { + _findclose(hFile); + errno = ENOMEM; + return NULL; + } + + memset(pdir, 0, sizeof(DIR)); + pdir->hFile = hFile; + memcpy(&pdir->c_file, &c_file, sizeof(c_file)); + pdir->first = 1; + + return pdir ; + } +} + +/* Close the directory stream DIRP. + Return 0 if successful, -1 if not. */ +int closedir(DIR *dirp) +{ + if ( dirp && (dirp->hFile) ) { + _findclose( dirp->hFile ); + dirp->hFile = 0; + free (dirp); + } + + return 0; +} + +/* Read a directory entry from DIRP. + Return a pointer to a `struct dirent' describing the entry, + or NULL for EOF or error. The storage returned may be overwritten + by a later readdir call on the same DIR stream. */ +struct dirent *readdir(void *avp) +{ + struct dirent *pdirentry; + struct _wfinddata_t c_file; + DIR *dirp = (DIR *)avp; + char *tmp = NULL; + + for (;;) { + if (dirp->first) { + memcpy(&c_file, &dirp->c_file, sizeof(c_file)); + dirp->first = 0; + } + else if (_wfindnext(dirp->hFile, &c_file) != 0) + return NULL; + + if (wcscmp(c_file.name, L".") == 0 || wcscmp(c_file.name, L"..") == 0 ) + continue; + + if ((pdirentry = malloc(sizeof(struct dirent))) == NULL || + (tmp = utf16_to_utf8(c_file.name)) == NULL) { + errno = ENOMEM; + return NULL; + } + + strncpy(pdirentry->d_name, tmp, strlen(tmp) + 1); + free(tmp); + + pdirentry->d_ino = 1; // a fictious one like UNIX to say it is nonzero + return pdirentry ; + } +} + +// return last part of a path. The last path being a filename. +char *basename(char *path) +{ + char *pdest; + + if (!path) + return "."; + pdest = strrchr(path, '/'); + if (pdest) + return (pdest+1); + pdest = strrchr(path, '\\'); + if (pdest) + return (pdest+1); + + return path; // path does not have a slash +} +// end of dirent functions in Windows diff --git a/contrib/win32/win32compat/win32_zlib.c b/contrib/win32/win32compat/win32_zlib.c new file mode 100644 index 000000000..0302ff815 --- /dev/null +++ b/contrib/win32/win32compat/win32_zlib.c @@ -0,0 +1,64 @@ +/* +* Author: Manoj Ampalam +* +* Implementation of POSIX APIs +* +* Copyright (c) 2016 Microsoft Corp. +* All rights reserved +* +* Dummy implementations of zlib routines used by OpenSSH +* +* 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 "inc\zlib.h" + + +int +deflateEnd(z_streamp strm) { + return Z_DATA_ERROR; +} + +int +inflateEnd(z_streamp strm) { + return Z_DATA_ERROR; +} + +int +deflateInit(z_streamp strm, int level) { + return Z_DATA_ERROR; +} + +int +inflateInit(z_streamp strm) { + return Z_DATA_ERROR; +} + +int +deflate(z_streamp strm, int flush) { + return Z_DATA_ERROR; +} + +int +inflate(z_streamp strm, int flush) { + return Z_DATA_ERROR; +} diff --git a/contrib/win32/win32compat/win32compat.vcproj b/contrib/win32/win32compat/win32compat.vcproj new file mode 100644 index 000000000..1de0f2545 --- /dev/null +++ b/contrib/win32/win32compat/win32compat.vcproj @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/contrib/win32/win32compat/wmain_common.c b/contrib/win32/win32compat/wmain_common.c new file mode 100644 index 000000000..b8418b8c4 --- /dev/null +++ b/contrib/win32/win32compat/wmain_common.c @@ -0,0 +1,53 @@ +/* +* Author: Manoj Ampalam +* +* Converts UTF-16 arguments to UTF-8 +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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 "inc\utf.h" + +int main(int, char **); +void w32posix_initialize(); + +int +wmain(int argc, wchar_t **wargv) { + char** argv = NULL; + int i; + + if (argc) { + if ((argv = malloc(argc * sizeof(char*))) == NULL) + fatal("out of memory"); + for (i = 0; i < argc; i++) + argv[i] = utf16_to_utf8(wargv[i]); + } + + w32posix_initialize(); + return main(argc, argv); +} diff --git a/contrib/win32/win32compat/wmain_sshd.c b/contrib/win32/win32compat/wmain_sshd.c new file mode 100644 index 000000000..7a812f0fe --- /dev/null +++ b/contrib/win32/win32compat/wmain_sshd.c @@ -0,0 +1,139 @@ +/* +* Author: Manoj Ampalam +* +* wmain entry for sshd. +* +* Copyright (c) 2015 Microsoft Corp. +* All rights reserved +* +* Microsoft openssh win32 port +* +* 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. +*/ + +/* disable inclusion of compatability defitnitions in CRT headers */ +#define __STDC__ 1 +#include +#include +#include "inc\utf.h" + +int main(int, char **); +void w32posix_initialize(); +extern HANDLE main_thread; +extern int is_child; + +int scm_start_service(DWORD, LPWSTR*); + +SERVICE_TABLE_ENTRYW dispatch_table[] = +{ + { L"sshd", (LPSERVICE_MAIN_FUNCTIONW)scm_start_service }, + { NULL, NULL } +}; +static SERVICE_STATUS_HANDLE service_status_handle; +static SERVICE_STATUS service_status; + + +static VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) +{ + service_status.dwCurrentState = dwCurrentState; + service_status.dwWin32ExitCode = dwWin32ExitCode; + service_status.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + service_status.dwControlsAccepted = 0; + else + service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) + service_status.dwCheckPoint = 0; + else + service_status.dwCheckPoint = 1; + + SetServiceStatus(service_status_handle, &service_status); +} + +BOOL WINAPI native_sig_handler(DWORD); +static VOID WINAPI service_handler(DWORD dwControl) +{ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: { + ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 500); + ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); + /* TOTO - GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); doesn't seem to be invoking + * signal handler (native_sig_handler) when sshd runs as service + * So calling the signal handler directly to interrupt the deamon's main thread + * This is being called after reporting SERVICE_STOPPED because main thread does a exit() + * as part of handling Crtl+c + */ + native_sig_handler(CTRL_C_EVENT); + return; + } + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } + + ReportSvcStatus(service_status.dwCurrentState, NO_ERROR, 0); +} + +char* w32_programdir(); +int sshd_main(int argc, wchar_t **wargv) { + char** argv = NULL; + int i; + + if (argc) { + if ((argv = malloc(argc * sizeof(char*))) == NULL) + fatal("out of memory"); + for (i = 0; i < argc; i++) + argv[i] = utf16_to_utf8(wargv[i]); + } + + w32posix_initialize(); + if (getenv("SSHD_REMSOC")) + is_child = 1; + /* change current directory to sshd.exe root */ + _wchdir(utf8_to_utf16(w32_programdir())); + return main(argc, argv); +} + +int wmain(int argc, wchar_t **wargv) { + + if (!StartServiceCtrlDispatcherW(dispatch_table)) { + if (GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) + return -1; + } + + return sshd_main(argc, wargv); +} + +int scm_start_service(DWORD num, LPWSTR* args) { + service_status_handle = RegisterServiceCtrlHandlerW(L"sshd", service_handler); + ZeroMemory(&service_status, sizeof(service_status)); + service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 300); + ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); + return sshd_main(num, args); +} + + diff --git a/defines.h b/defines.h index c89f85a8d..b9df7b899 100644 --- a/defines.h +++ b/defines.h @@ -784,6 +784,11 @@ struct winsize { # define CUSTOM_SYS_AUTH_PASSWD 1 #endif +#ifdef WINDOWS +/* Windows has custom non-BSD logic for password auth */ +# define CUSTOM_SYS_AUTH_PASSWD 1 +#endif /* WINDOWS */ + #if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(HAVE_SECUREWARE) # define CUSTOM_SYS_AUTH_PASSWD 1 #endif diff --git a/dns.c b/dns.c index e813afeae..3af5cd007 100644 --- a/dns.c +++ b/dns.c @@ -204,6 +204,10 @@ int verify_host_key_dns(const char *hostname, struct sockaddr *address, struct sshkey *hostkey, int *flags) { +#ifdef WINDOWS + error("dns host key verification is not supported in Windows yet"); + return -1; +#else /* !WINDOWS */ u_int counter; int result; struct rrsetinfo *fingerprints = NULL; @@ -306,6 +310,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, debug("no host key fingerprint found in DNS"); return 0; +#endif /* !WINDOWS */ } /* diff --git a/hostfile.c b/hostfile.c index 4548fbab3..6543ac8ad 100644 --- a/hostfile.c +++ b/hostfile.c @@ -531,6 +531,11 @@ int hostfile_replace_entries(const char *filename, const char *host, const char *ip, struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg) { +#ifdef WINDOWS + error("replacing host file entries is not supported in Windows yet"); + errno = ENOTSUP; + return -1; +#else /* !WINDOWS */ int r, fd, oerrno = 0; int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE; struct host_delete_ctx ctx; @@ -645,6 +650,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, if (r == SSH_ERR_SYSTEM_ERROR) errno = oerrno; return r; +#endif /* !WINDOWS */ } static int diff --git a/log.c b/log.c index 2b59c4274..53721f3bf 100644 --- a/log.c +++ b/log.c @@ -454,7 +454,15 @@ do_log(LogLevel level, const char *fmt, va_list args) log_handler = tmp_handler; } else if (log_on_stderr) { snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); +#ifdef WINDOWS + /* + * In Windows, write is implemented as part of POSIX compat layer + * that itself may "log" resulting in a infinite recursion loop + */ + _write(STDERR_FILENO, msgbuf, strlen(msgbuf)); +#else /* !WINDOWS */ (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); +#endif /* !WINDOWS */ } else { #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); diff --git a/loginrec.c b/loginrec.c index 788553e92..b1c27ebe8 100644 --- a/loginrec.c +++ b/loginrec.c @@ -530,6 +530,7 @@ getlast_entry(struct logininfo *li) /* If wtmp isn't available, try wtmpx */ return (wtmpx_get_entry(li)); # else + /* TODO - implement last_login_entry in Windows*/ /* Give up: No means of retrieving last login time */ return (0); # endif /* DISABLE_LASTLOG */ diff --git a/misc.c b/misc.c index 65c9222aa..3dfcef6f4 100644 --- a/misc.c +++ b/misc.c @@ -435,6 +435,17 @@ colon(char *cp) if (*cp == ':') /* Leading colon is part of file name. */ return NULL; + +#ifdef WINDOWS + /* + * Account for Windows file names in the form x: or /x: + * Note: This may conflict with potential single charecter targets + */ + if ((*cp != '\0' && cp[1] == ':') || + (cp[0] == '/' && cp[1] != '\0' && cp[2] == ':')) + return NULL; +#endif + if (*cp == '[') flag = 1; @@ -783,6 +794,10 @@ tun_open(int tun, int mode) void sanitise_stdfd(void) { +#ifdef WINDOWS + /* nothing to do for Windows*/ + return; +#else /* !WINDOWS */ int nullfd, dupfd; if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { @@ -801,6 +816,7 @@ sanitise_stdfd(void) } if (nullfd > STDERR_FILENO) close(nullfd); +#endif /* !WINDOWS */ } char * @@ -1253,6 +1269,14 @@ bind_permitted(int port, uid_t uid) } /* returns 1 if process is already daemonized, 0 otherwise */ +#ifdef WINDOWS +/* This should go away once sshd platform specific startup code is refactored */ +int +daemonized(void) +{ + return 1; +} +#else /* !WINDOWS */ int daemonized(void) { @@ -1269,3 +1293,4 @@ daemonized(void) debug3("already daemonized"); return 1; } +#endif /* !WINDOWS */ diff --git a/myproposal.h b/myproposal.h index 072e36ec7..aa7ac892e 100644 --- a/myproposal.h +++ b/myproposal.h @@ -167,7 +167,12 @@ #endif /* WITH_OPENSSL */ +#ifdef WINDOWS +/* compression not supported in Windows yet */ +#define KEX_DEFAULT_COMP "none" +#else /* !WINDOWS */ #define KEX_DEFAULT_COMP "none,zlib@openssh.com" +#endif /* !WINDOWS */ #define KEX_DEFAULT_LANG "" #define KEX_CLIENT \ diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index cff547745..2beb30011 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -234,7 +234,10 @@ long long strtonum(const char *, long long, long long, const char **); # define wcwidth(x) (((x) >= 0x20 && (x) <= 0x7e) ? 1 : -1) /* force our no-op nl_langinfo and mbtowc */ # undef HAVE_NL_LANGINFO +#ifndef WINDOWS +/* Windows does not have wcwidth but does have mbtowc*/ # undef HAVE_MBTOWC +#endif /* WINDOWS */ # undef HAVE_LANGINFO_H #endif diff --git a/progressmeter.c b/progressmeter.c index fe9bf52e4..786d0c685 100644 --- a/progressmeter.c +++ b/progressmeter.c @@ -81,7 +81,12 @@ static const char unit[] = " KMGT"; static int can_output(void) { +#ifdef WINDOWS + /* TODO - confirm this is always true */ + return 1; +#else /* !WINDOWS */ return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); +#endif /* !WINDOWS */ } static void diff --git a/readconf.c b/readconf.c index fa3fab8f0..bf52589f6 100644 --- a/readconf.c +++ b/readconf.c @@ -470,6 +470,10 @@ static int execute_in_shell(const char *cmd) { char *shell; +#ifdef WINDOWS + fatal("LocalCommand execution is not supported on Windows yet"); + return 0; +#else /* !WINDOWS */ pid_t pid; int devnull, status; extern uid_t original_real_uid; @@ -527,6 +531,7 @@ execute_in_shell(const char *cmd) } debug3("command returned status %d", WEXITSTATUS(status)); return WEXITSTATUS(status); +#endif /* !WINDOWS */ } /* @@ -1710,6 +1715,7 @@ read_config_file_depth(const char *filename, struct passwd *pw, if ((f = fopen(filename, "r")) == NULL) return 0; +#ifndef WINDOWS /* TODO - implement permission checks for Windows */ if (flags & SSHCONF_CHECKPERM) { struct stat sb; @@ -1719,6 +1725,7 @@ read_config_file_depth(const char *filename, struct passwd *pw, (sb.st_mode & 022) != 0)) fatal("Bad owner or permissions on %s", filename); } +#endif /* !WINDOWS */ debug("Reading configuration data %.200s", filename); diff --git a/readpass.c b/readpass.c index 05c8cac1c..78f8f07f2 100644 --- a/readpass.c +++ b/readpass.c @@ -66,7 +66,14 @@ ssh_askpass(char *askpass, const char *msg) return NULL; } osigchld = signal(SIGCHLD, SIG_DFL); +#ifdef WINDOWS + /* spawd child for Windows */ + fcntl(p[0], F_SETFD, FD_CLOEXEC); + pid = spawn_child(askpass, p[1], p[1], STDERR_FILENO, 0); + if (pid < 0) { +#else /* !WINDOWS */ if ((pid = fork()) < 0) { +#endif /* !WINDOWS */ error("ssh_askpass: fork: %s", strerror(errno)); signal(SIGCHLD, osigchld); return NULL; @@ -118,6 +125,71 @@ ssh_askpass(char *askpass, const char *msg) char * read_passphrase(const char *prompt, int flags) { + +#ifdef WINDOWS + /* TODO - do flags apply on Windows? */ + char *askpass = NULL; + char *ret = NULL; + char buf[1024] = { 0 }; + + DWORD mode; + size_t len = 0; + int retr = 0; + + if (getenv(SSH_ASKPASS_ENV)) { + askpass = getenv(SSH_ASKPASS_ENV); + if ((ret = ssh_askpass(askpass, prompt)) == NULL) + return xstrdup(""); + return ret; + } + + /* prompt user */ + wchar_t* wtmp = utf8_to_utf16(prompt); + if (wtmp == NULL) + fatal("unable to alloc memory"); + _cputws(wtmp); + free(wtmp); + + len = retr = 0; + int bufsize = sizeof(buf); + + while (_kbhit()) + _getch(); + + while (len < bufsize) { + buf[len] = (unsigned char)_getch(); + + if (buf[len] == '\r') { + if (_kbhit()) /* read linefeed if its there */ + _getch(); + break; + } + else if (buf[len] == '\n') { + break; +} + else if (buf[len] == '\b') { /* backspace */ + if (len > 0) + len--; /* overwrite last character */ + } + else if (buf[len] == '\003') { + /* exit on Ctrl+C */ + fatal(""); + } + else { + len++; /* keep reading in the loop */ + } + } + + buf[len] = '\0'; /* get rid of the cr/lf */ + _cputs("\n"); /*show a newline as we do not echo password or the line */ + + ret = xstrdup(buf); + + memset(buf, 'x', sizeof(buf)); + + return ret; + +#else /* !WINDOWS */ char *askpass = NULL, *ret, buf[1024]; int rppflags, use_askpass = 0, ttyfd; @@ -164,6 +236,7 @@ read_passphrase(const char *prompt, int flags) ret = xstrdup(buf); explicit_bzero(buf, sizeof(buf)); return ret; +#endif /* !WINDOWS */ } int diff --git a/scp.c b/scp.c index b4db85198..57b037e39 100644 --- a/scp.c +++ b/scp.c @@ -195,6 +195,26 @@ do_local_cmd(arglist *a) fmprintf(stderr, " %s", a->list[i]); fprintf(stderr, "\n"); } +#ifdef WINDOWS + /* flatten the cmd into a long space separated string and execute using system(cmd) api */ + { + char* cmd; + size_t cmdlen = 0; + for (i = 0; i < a->num; i++) + cmdlen += strlen(a->list[i]) + 1; + + cmd = xmalloc(cmdlen); + cmd[0] = '\0'; + for (i = 0; i < a->num; i++) { + strcat(cmd, a->list[i]); + strcat(cmd, " "); + } + if (system(cmd)) + return -1; + return 0; + } + +#else /* !WINDOWS */ if ((pid = fork()) == -1) fatal("do_local_cmd: fork: %s", strerror(errno)); @@ -219,6 +239,7 @@ do_local_cmd(arglist *a) return (-1); return (0); +#endif /* !WINDOWS */ } /* @@ -260,7 +281,43 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) signal(SIGTTOU, suspchild); /* Fork a child to execute the command on the remote host using ssh. */ +#ifdef WINDOWS + /* generate command line and spawn_child */ + replacearg(&args, 0, "%s", ssh_program); + if (remuser != NULL) { + addargs(&args, "-l"); + addargs(&args, "%s", remuser); + } + addargs(&args, "--"); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); + + { + char* full_cmd; + size_t cmdlen = 0; + char** list = args.list; + + cmdlen = 1; /* null term */ + while (*list) + cmdlen += strlen(*list++) + 1; + + full_cmd = xmalloc(cmdlen); + full_cmd[0] = '\0'; + list = args.list; + while (*list) { + strcat(full_cmd, *list++); + strcat(full_cmd, " "); + } + + fcntl(pout[0], F_SETFD, FD_CLOEXEC); + fcntl(pin[1], F_SETFD, FD_CLOEXEC); + + do_cmd_pid = spawn_child(full_cmd, pin[0], pout[1], STDERR_FILENO, 0); + free(full_cmd); + } +#else /* !WINDOWS */ do_cmd_pid = fork(); +#endif /* !WINDOWS */ if (do_cmd_pid == 0) { /* Child. */ close(pin[1]); @@ -297,7 +354,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) } /* - * This functions executes a command simlar to do_cmd(), but expects the + * This functions executes a command similar to do_cmd(), but expects the * input and output descriptors to be setup by a previous call to do_cmd(). * This way the input and output of two commands can be connected. */ @@ -314,7 +371,42 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) remuser ? remuser : "(unspecified)", cmd); /* Fork a child to execute the command on the remote host using ssh. */ +#ifdef WINDOWS + /* generate command line and spawn_child */ + replacearg(&args, 0, "%s", ssh_program); + if (remuser != NULL) { + addargs(&args, "-l"); + addargs(&args, "%s", remuser); + } + addargs(&args, "--"); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); + + { + char* full_cmd; + size_t cmdlen = 0; + char** list = args.list; + + cmdlen = strlen(w32_programdir()) + 2; + while (*list) + cmdlen += strlen(*list++) + 1; + + full_cmd = xmalloc(cmdlen); + full_cmd[0] = '\0'; + strcat(full_cmd, w32_programdir()); + strcat(full_cmd, "\\"); + list = args.list; + while (*list) { + strcat(full_cmd, *list++); + strcat(full_cmd, " "); + } + + pid = spawn_child(full_cmd, fdin, fdout, STDERR_FILENO, 0); + free(full_cmd); + } +#else /* !WINDOWS */ pid = fork(); +#endif /* !WINDOWS */ if (pid == 0) { dup2(fdin, 0); dup2(fdout, 1); @@ -500,6 +592,24 @@ main(int argc, char **argv) remin = STDIN_FILENO; remout = STDOUT_FILENO; +#ifdef WINDOWS + /* + * To support both Windows and Unix style paths + * convert '\\' to '/' in rest of arguments + */ + { + char *s1, *s2; + int i; + for (i = 0; i < argc; i++) { + s1 = argv[i]; + while ((s2 = strchr(s1, '\\')) != NULL) { + *s2 = '/'; + s1 = s2 + 1; + } + } + } +#endif /* WINDOWS */ + if (fflag) { /* Follow "protocol", send data. */ (void) response(); @@ -715,6 +825,47 @@ tolocal(int argc, char **argv) for (i = 0; i < argc - 1; i++) { if (!(src = colon(argv[i]))) { /* Local to local. */ freeargs(&alist); +#ifdef WINDOWS +#define _PATH_XCOPY "xcopy" +#define _PATH_COPY "copy" + /* local to local on windows - need to use local native copy command */ + struct stat stb; + int exists; + + exists = stat(argv[i], &stb) == 0; + if (exists && (S_ISDIR(stb.st_mode))) { + addargs(&alist, "%s", _PATH_XCOPY); + if (iamrecursive) + addargs(&alist, "/S /E /H"); + if (pflag) + addargs(&alist, "/K /X"); + addargs(&alist, "/Y /F /I"); + addargs(&alist, "%s", argv[i]); + + char *lastf = NULL, *lastr = NULL, *name; + if ((lastf = strrchr(argv[i], '/')) == NULL && (lastr = strrchr(argv[i], '\\')) == NULL) + name = argv[i]; + else { + if (lastf) + name = lastf; + if (lastr) + name = lastr; + ++name; + } + + char * dest = argv[argc - 1]; + int len = strlen(dest); + char * lastletter = dest + len - 1; + + addargs(&alist, "%s%s%s", argv[argc - 1], + (lastletter == "\\" || lastletter == "/") ? "" : "\\", name); + } else { + addargs(&alist, "%s", _PATH_COPY); + addargs(&alist, "/Y"); + addargs(&alist, "%s", argv[i]); + addargs(&alist, "%s", argv[argc - 1]); + } +#else /* !WINDOWS */ addargs(&alist, "%s", _PATH_CP); if (iamrecursive) addargs(&alist, "-r"); @@ -723,6 +874,7 @@ tolocal(int argc, char **argv) addargs(&alist, "--"); addargs(&alist, "%s", argv[i]); addargs(&alist, "%s", argv[argc-1]); +#endif /* !WINDOWS */ if (do_local_cmd(&alist)) ++errs; continue; @@ -891,7 +1043,17 @@ rsource(char *name, struct stat *statp) (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", (u_int) (statp->st_mode & FILEMODEMASK), 0, last); if (verbose_mode) +#ifdef WINDOWS + /* TODO - make fmprintf work for Windows */ + { + printf("Entering directory: "); + wchar_t* wtmp = utf8_to_utf16(path); + WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), wtmp, wcslen(wtmp), 0, 0); + free(wtmp); + } +#else /* !WINDOWS */ fmprintf(stderr, "Entering directory: %s", path); +#endif /* !WINDOWS */ (void) atomicio(vwrite, remout, path, strlen(path)); if (response() < 0) { closedir(dirp); @@ -966,7 +1128,17 @@ sink(int argc, char **argv) } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); *cp = 0; if (verbose_mode) +#ifdef WINDOWS + /* TODO - make fmprintf work for Windows */ + { + printf("Sink: "); + wchar_t* wtmp = utf8_to_utf16(buf); + WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), wtmp, wcslen(wtmp), 0, 0); + free(wtmp); + } +#else /* !WINDOWS */ fmprintf(stderr, "Sink: %s", buf); +#endif /* !WINDOWS */ if (buf[0] == '\01' || buf[0] == '\02') { if (iamremote == 0) { diff --git a/servconf.c b/servconf.c index 795ddbab7..3b82322dc 100644 --- a/servconf.c +++ b/servconf.c @@ -604,7 +604,12 @@ derelativise_path(const char *path) if (strcasecmp(path, "none") == 0) return xstrdup("none"); expanded = tilde_expand_filename(path, getuid()); +#ifdef WINDOWS + /* Windows absolute paths have a drive letter followed by :*/ + if (*expanded != '\0' && expanded[1] == ':') +#else /* !WINDOWS */ if (*expanded == '/') +#endif /* !WINDOWS */ return expanded; if (getcwd(cwd, sizeof(cwd)) == NULL) fatal("%s: getcwd: %s", __func__, strerror(errno)); diff --git a/session.c b/session.c index a08aa69d1..c0fb6d7c1 100644 --- a/session.c +++ b/session.c @@ -182,6 +182,10 @@ auth_sock_cleanup_proc(struct passwd *pw) static int auth_input_request_forwarding(struct passwd * pw) { +#ifdef WINDOWS + packet_send_debug("Agent forwarding not supported yet in Windows"); + return 0; +#else /* !WINDOWS */ Channel *nc; int sock = -1; @@ -238,6 +242,7 @@ auth_input_request_forwarding(struct passwd * pw) auth_sock_name = NULL; auth_sock_dir = NULL; return 0; +#endif /* !WINDOWS */ } static void @@ -285,6 +290,361 @@ xauth_valid_string(const char *s) } #define USE_PIPES 1 + +#ifdef WINDOWS +/* + * do_exec* on Windows + * - Read and set user environment variables from registry + * - Build subsystem cmdline path + * - Interactive shell/commands are executed using ssh-shellhost.exe + * - ssh-shellhost.exe implements server-side PTY for Windows + */ +#include +#include + +#define SET_USER_ENV(folder_id, evn_variable) do { \ + if (SHGetKnownFolderPath(&folder_id,0,token,&path) == S_OK) \ + { \ + SetEnvironmentVariableW(evn_variable, path); \ + CoTaskMemFree(path); \ + } \ +} while (0) + +void setup_session_vars(Session* s) +{ + wchar_t* pw_dir_w; + wchar_t* tmp; + char buf[128]; + char* laddr; + + struct ssh *ssh = active_state; /* XXX */ + + if ((pw_dir_w = utf8_to_utf16(s->pw->pw_dir)) == NULL) + fatal("%s: out of memory"); + + if ((tmp = utf8_to_utf16(s->pw->pw_name)) == NULL) + fatal("%s, out of memory"); + SetEnvironmentVariableW(L"USERNAME", tmp); + free(tmp); + + if (s->display) + SetEnvironmentVariableA("DISPLAY", s->display); + + + SetEnvironmentVariableW(L"HOMEPATH", pw_dir_w); + SetEnvironmentVariableW(L"USERPROFILE", pw_dir_w); + + if (pw_dir_w[1] == L':') { + wchar_t wc = pw_dir_w[2]; + pw_dir_w[2] = L'\0'; + SetEnvironmentVariableW(L"HOMEDRIVE", pw_dir_w); + pw_dir_w[2] = wc; + } + + snprintf(buf, sizeof buf, "%.50s %d %d", + ssh->remote_ipaddr, ssh->remote_port, ssh->local_port); + + SetEnvironmentVariableA("SSH_CLIENT", buf); + + laddr = get_local_ipaddr(packet_get_connection_in()); + + snprintf(buf, sizeof buf, "%.50s %d %.50s %d", + ssh->remote_ipaddr, ssh->remote_port, laddr, ssh->local_port); + + free(laddr); + + SetEnvironmentVariableA("SSH_CONNECTION", buf); + + if (original_command) + SetEnvironmentVariableA("SSH_ORIGINAL_COMMAND", original_command); + + + if ((s->term) && (s->term[0])) + SetEnvironmentVariable("TERM", s->term); + + if (!s->is_subsystem) { + snprintf(buf, sizeof buf, "%s@%s $P$G", s->pw->pw_name, getenv("COMPUTERNAME")); + SetEnvironmentVariableA("PROMPT", buf); + } + + /*set user environment variables*/ + { + UCHAR InfoBuffer[1000]; + PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer; + DWORD dwInfoBufferSize, tmp_len; + LPWSTR sid_str = NULL; + wchar_t reg_path[MAX_PATH]; + HKEY reg_key = 0; + HANDLE token = s->authctxt->methoddata; + + tmp_len = MAX_PATH; + if (GetTokenInformation(token, TokenUser, InfoBuffer, + 1000, &dwInfoBufferSize) == FALSE || + ConvertSidToStringSidW(pTokenUser->User.Sid, &sid_str) == FALSE || + swprintf(reg_path, MAX_PATH, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", sid_str) == MAX_PATH || + RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®_key) != 0 || + RegQueryValueExW(reg_key, L"ProfileImagePath", 0, NULL, (LPBYTE)pw_dir_w, &tmp_len) != 0) { + /* one of the above failed */ + debug("cannot retirve profile path - perhaps user profile is not created yet"); + } + + if (sid_str) + LocalFree(sid_str); + + if (reg_key) + RegCloseKey(reg_key); + + /* retrieve and set env variables. */ + { +#define MAX_VALUE_LEN 1000 +#define MAX_DATA_LEN 2000 +#define MAX_EXPANDED_DATA_LEN 5000 + /* TODO - Get away with fixed limits and dynamically allocate required memory, cleanup this logic*/ + wchar_t *path; + wchar_t value_name[MAX_VALUE_LEN]; + wchar_t value_data[MAX_DATA_LEN], value_data_expanded[MAX_EXPANDED_DATA_LEN], *to_apply; + DWORD value_type, name_len, data_len; + int i; + LONG ret; + + if (ImpersonateLoggedOnUser(token) == FALSE) + debug("Failed to impersonate user token, %d", GetLastError()); + SET_USER_ENV(FOLDERID_LocalAppData, L"LOCALAPPDATA"); + SET_USER_ENV(FOLDERID_Profile, L"USERPROFILE"); + SET_USER_ENV(FOLDERID_RoamingAppData, L"APPDATA"); + reg_key = 0; + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0, KEY_QUERY_VALUE, ®_key) == ERROR_SUCCESS) { + i = 0; + while (1) { + name_len = MAX_VALUE_LEN * 2; + data_len = MAX_DATA_LEN * 2; + to_apply = NULL; + if (RegEnumValueW(reg_key, i++, value_name, &name_len, 0, &value_type, (LPBYTE)&value_data, &data_len) != ERROR_SUCCESS) + break; + if (value_type == REG_SZ) + to_apply = value_data; + else if (value_type == REG_EXPAND_SZ) { + ExpandEnvironmentStringsW(value_data, value_data_expanded, MAX_EXPANDED_DATA_LEN); + to_apply = value_data_expanded; + } + + if (wcsicmp(value_name, L"PATH") == 0) { + DWORD size; + if ((size = GetEnvironmentVariableW(L"PATH", NULL, 0)) != ERROR_ENVVAR_NOT_FOUND) { + memcpy(value_data_expanded + size, to_apply, (wcslen(to_apply) + 1) * 2); + GetEnvironmentVariableW(L"PATH", value_data_expanded, MAX_EXPANDED_DATA_LEN); + value_data_expanded[size - 1] = L';'; + to_apply = value_data_expanded; + } + + } + if (to_apply) + SetEnvironmentVariableW(value_name, to_apply); + } + RegCloseKey(reg_key); + } + RevertToSelf(); + } + } + + free(pw_dir_w); +} + +int do_exec_windows(Session *s, const char *command, int pty) { + int pipein[2], pipeout[2], pipeerr[2], r; + char *exec_command = NULL, *progdir = w32_programdir(); + wchar_t *exec_command_w = NULL, *pw_dir_w; + + if (s->is_subsystem >= SUBSYSTEM_INT_SFTP_ERROR) { + error("sub system not supported, exiting\n"); + fflush(NULL); + exit(1); + } + + /* Create three pipes for stdin, stdout and stderr */ + if (pipe(pipein) == -1 || pipe(pipeout) == -1 || pipe(pipeerr) == -1) + fatal("%s: cannot create pipe: %.100s", __func__, strerror(errno)); + + if ((pw_dir_w = utf8_to_utf16(s->pw->pw_dir)) == NULL) + fatal("%s: out of memory"); + + + set_nonblock(pipein[0]); + set_nonblock(pipein[1]); + set_nonblock(pipeout[0]); + set_nonblock(pipeout[1]); + set_nonblock(pipeerr[0]); + set_nonblock(pipeerr[1]); + + fcntl(pipein[1], F_SETFD, FD_CLOEXEC); + fcntl(pipeout[0], F_SETFD, FD_CLOEXEC); + fcntl(pipeerr[0], F_SETFD, FD_CLOEXEC); + + /* prepare exec - path used with CreateProcess() */ + if (s->is_subsystem || (command && memcmp(command, "scp", 3) == 0)) { + /* relative or absolute */ + if (command == NULL || command[0] == '\0') + fatal("expecting command for a subsystem"); + + if (command[1] == ':') /* absolute */ + exec_command = xstrdup(command); + else {/*relative*/ + exec_command = malloc(strlen(progdir) + 1 + strlen(command)); + if (exec_command == NULL) + fatal("%s, out of memory"); + memcpy(exec_command, progdir, strlen(progdir)); + exec_command[strlen(progdir)] = '\\'; + memcpy(exec_command + strlen(progdir) + 1, command, strlen(command) + 1); + } + } else { + char *shell_host = pty ? "ssh-shellhost.exe " : "ssh-shellhost.exe -nopty ", *c; + exec_command = malloc(strlen(progdir) + 1 + strlen(shell_host) + (command ? strlen(command) : 0) + 1); + if (exec_command == NULL) + fatal("%s, out of memory"); + c = exec_command; + memcpy(c, progdir, strlen(progdir)); + c += strlen(progdir); + *c++ = '\\'; + memcpy(c, shell_host, strlen(shell_host)); + c += strlen(shell_host); + if (command) { + memcpy(c, command, strlen(command)); + c += strlen(command); + } + *c = '\0'; + } + + /* setup Environment varibles */ + setup_session_vars(s); + extern int debug_flag; + + { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + BOOL b; + + HANDLE hToken = INVALID_HANDLE_VALUE; + + + /* + * Assign sockets to StartupInfo + */ + + memset(&si, 0, sizeof(STARTUPINFO)); + + si.cb = sizeof(STARTUPINFO); + si.lpReserved = 0; + si.lpTitle = NULL; /* NULL means use exe name as title */ + si.dwX = 0; + si.dwY = 0; + si.dwXSize = 5; + si.dwYSize = 5; + si.dwXCountChars = s->col; + si.dwYCountChars = s->row; + si.dwFillAttribute = 0; + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESIZE | STARTF_USECOUNTCHARS; + si.wShowWindow = 0; // FALSE ; + si.cbReserved2 = 0; + si.lpReserved2 = 0; + + si.hStdInput = (HANDLE)sfd_to_handle(pipein[0]); + si.hStdOutput = (HANDLE)sfd_to_handle(pipeout[1]); + si.hStdError = (HANDLE)sfd_to_handle(pipeerr[1]); + si.lpDesktop = NULL; + + hToken = s->authctxt->methoddata; + + debug("Executing command: %s", exec_command); + + /* Create the child process */ + + exec_command_w = utf8_to_utf16(exec_command); + + if (debug_flag) + b = CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE, + DETACHED_PROCESS, NULL, pw_dir_w, + &si, &pi); + else + b = CreateProcessAsUserW(hToken, NULL, exec_command_w, NULL, NULL, TRUE, + DETACHED_PROCESS , NULL, pw_dir_w, + &si, &pi); + + if (!b) + { + debug("ERROR. Cannot create process (%u).\n", GetLastError()); + free(pw_dir_w); + free(exec_command_w); + CloseHandle(hToken); + + exit(1); + } + else if (pty) { /*attach to shell console */ + FreeConsole(); + if (!debug_flag) + ImpersonateLoggedOnUser(hToken); + Sleep(20); + while (AttachConsole(pi.dwProcessId) == FALSE) { + DWORD exit_code; + if (GetExitCodeProcess(pi.hProcess, &exit_code) && exit_code != STILL_ACTIVE) + break; + Sleep(100); + } + if (!debug_flag) + RevertToSelf(); + { + /* TODO - check this - Create Process above is not respecting x# and y# chars, so we are doing this explicity on the + * attached console agein */ + + COORD coord; + coord.X = s->col; + coord.Y = 9999;; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord); + } + } + + CloseHandle(pi.hThread); + s->pid = pi.dwProcessId; + sw_add_child(pi.hProcess, pi.dwProcessId); + } + /* + * Set interactive/non-interactive mode. + */ + packet_set_interactive(s->display != NULL, options.ip_qos_interactive, + options.ip_qos_bulk); + + /* Close the child sides of the socket pairs. */ + close(pipein[0]); + close(pipeout[1]); + close(pipeerr[1]); + + /* + * Enter the interactive session. Note: server_loop must be able to + * handle the case that fdin and fdout are the same. + */ + + if (s->ttyfd == -1) + session_set_fds(s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 0); + else + session_set_fds(s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 1); // tty interactive session + + free(pw_dir_w); + free(exec_command_w); + return 0; + +} + +int +do_exec_no_pty(Session *s, const char *command) { + return do_exec_windows(s, command, 0); +} + +int +do_exec_pty(Session *s, const char *command) { + return do_exec_windows(s, command, 1); +} + +#else /* !WINDOWS */ /* * This is called to fork and execute a command when we have no tty. This * will call do_child from the child, and server_loop from the parent after @@ -578,6 +938,7 @@ do_exec_pty(Session *s, const char *command) session_set_fds(s, ptyfd, fdout, -1, 1, 1); return 0; } +#endif /* !WINDOWS */ #ifdef LOGIN_NEEDS_UTMPX static void @@ -1477,6 +1838,10 @@ child_close_fds(void) void do_child(Session *s, const char *command) { +#ifdef WINDOWS + /*not called for Windows */ + return; +#else /* !WINDOWS */ extern char **environ; char **env; char *argv[ARGV_MAX]; @@ -1677,6 +2042,7 @@ do_child(Session *s, const char *command) execve(shell, argv, env); perror(shell); exit(1); +#endif /* !WINDOWS */ } void diff --git a/sftp.c b/sftp.c index 2b8fdabfb..1d3d62afd 100644 --- a/sftp.c +++ b/sftp.c @@ -292,9 +292,40 @@ help(void) "? Synonym for help\n"); } +#ifdef WINDOWS +/* printf version to account for utf-8 input */ +/* TODO - merge this with vfmprint */ +static void printf_utf8(char *fmt, ... ) { + /* TODO - is 1024 sufficient */ + char buf[1024]; + wchar_t* wtmp; + va_list valist; + va_start(valist, fmt); + + vsnprintf(buf, 1024, fmt, valist); + va_end(valist); + + if ((wtmp = utf8_to_utf16(buf)) == NULL) + fatal("unable to allocate memory"); + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wtmp, wcslen(wtmp), 0, 0); + free(wtmp); +} + +/* override mprintf */ +#define mprintf(a,...) printf_utf8((a), __VA_ARGS__) +#endif /* WINDOWS */ + static void local_do_shell(const char *args) { + #ifdef WINDOWS + /* execute via system call in Windows*/ + if (!*args) { + /* TODO - support unicode ComSpec */ + args = (char *) getenv("ComSpec"); // get name of Windows cmd shell + } + system(args); // execute the shell or cmd given + #else /* !WINDOWS */ int status; char *shell; pid_t pid; @@ -328,6 +359,7 @@ local_do_shell(const char *args) error("Shell exited abnormally"); else if (WEXITSTATUS(status)) error("Shell exited with status %d", WEXITSTATUS(status)); + #endif /* !WINDOWS */ } static void @@ -371,12 +403,45 @@ make_absolute(char *p, const char *pwd) char *abs_str; /* Derelativise */ +#ifdef WINDOWS + /* + * For Windows - given path is absolute when + * - first character is "/" + * - or second character is ":" + * This code is also applicable from a Linux client to Windows target + * Need to follow up with community if this makes sense in common code + */ + char *s1, *s2; + if (p && p[0] != '/' && (p[0] == '\0' || p[1] != ':')) { + abs_str = path_append(pwd, p); + free(p); + p = abs_str; + } + + /* convert '\\' tp '/' */ + s1 = p; + while ((s2 = strchr(s1, '\\')) != NULL) { + *s2 = '/'; + s1 = s2 + 1; + } + + /* Append "/" if needed to the absolute windows path */ + if (p && p[0] != '\0' && p[1] == ':') { + s1 = path_append("/", p); + free(p); + p = s1; + } + +#else /* !WINDOWS */ if (p && p[0] != '/') { abs_str = path_append(pwd, p); free(p); return(abs_str); } else return(p); +#endif /* !WINDOWS */ + return(p); + } static int @@ -791,6 +856,7 @@ sdirent_comp(const void *aa, const void *bb) return (rmul * NCMP(a->a.size, b->a.size)); fatal("Unknown ls sort type"); + return 0; } /* sftp ls.1 replacement for directories */ @@ -861,7 +927,17 @@ do_ls_dir(struct sftp_conn *conn, const char *path, } else mprintf("%s\n", d[n]->longname); } else { +#ifdef WINDOWS + /* cannot use printf_utf8 becuase of width specification */ + /* printf_utf8 does not account for utf-16 based argument widths */ + wchar_t buf[1024]; + wchar_t* wtmp = utf8_to_utf16(fname); + swprintf(buf, 1024, L"%-*s", colspace, wtmp); + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), buf, wcslen(buf), 0, 0); + free(wtmp); +#else mprintf("%-*s", colspace, fname); +#endif if (c >= columns) { printf("\n"); c = 1; @@ -945,7 +1021,17 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, mprintf("%s\n", lname); free(lname); } else { +#ifdef WINDOWS + /* cannot use printf_utf8 becuase of width specification */ + /* printf_utf8 does not account for utf-16 based argument widths */ + wchar_t buf[1024]; + wchar_t* wtmp = utf8_to_utf16(fname); + swprintf(buf, 1024, L"%-*s", colspace, wtmp); + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), buf, wcslen(buf), 0, 0); + free(wtmp); +#else mprintf("%-*s", colspace, fname); +#endif if (c >= columns) { printf("\n"); c = 1; @@ -1425,6 +1511,19 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, glob_t g; path1 = path2 = NULL; +#ifdef WINDOWS + /* + * convert '\\' to '/' in Windows styled paths. + * else they get treated as escape sequence in makeargv + */ + { + char *s1 = cmd, *s2; + while ((s2 = strchr(s1, '\\')) != NULL) { + *s2 = '/'; + s1 = s2 + 1; + } + } +#endif cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); if (ignore_errors != 0) @@ -2105,8 +2204,14 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) free(dir); } +#ifdef WINDOWS + /* Min buffer size allowed in Windows is 2*/ + setvbuf(stdout, NULL, _IOLBF, 2); + setvbuf(infile, NULL, _IOLBF, 2); +#else /* !WINDOWS */ setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); +#endif /* !WINDOWS */ interactive = !batchmode && isatty(STDIN_FILENO); err = 0; @@ -2116,6 +2221,25 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) signal(SIGINT, SIG_IGN); if (el == NULL) { +#ifdef WINDOWS + /* fgets on Windows does not support Unicode input*/ + if (interactive) { + wchar_t wcmd[2048]; + printf("sftp> "); + if (fgetws(wcmd, sizeof(cmd)/sizeof(wchar_t), infile) == NULL) { + printf("\n"); + break; + } + else { + char *pcmd = NULL; + if ((pcmd = utf16_to_utf8(wcmd)) == NULL) + fatal("failed to convert input arguments"); + strcpy(cmd, pcmd); + free(pcmd); + } + } else if (fgets(cmd, sizeof(cmd), infile) == NULL) + break; +#else /* !WINDOWS */ if (interactive) printf("sftp> "); if (fgets(cmd, sizeof(cmd), infile) == NULL) { @@ -2123,6 +2247,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) printf("\n"); break; } +#endif/* !WINDOWS */ if (!interactive) { /* Echo command */ mprintf("sftp> %s", cmd); if (strlen(cmd) > 0 && @@ -2195,7 +2320,37 @@ connect_to_server(char *path, char **args, int *in, int *out) c_in = c_out = inout[1]; #endif /* USE_PIPES */ +#ifdef WINDOWS + /* fork replacement on Windows */ + { + size_t cmdlen = 0; + int i = 0; + char* full_cmd; + + cmdlen = strlen(path) + 1; + for (i = 1; args[i]; i++) + cmdlen += strlen(args[i]) + 1; + + full_cmd = xmalloc(cmdlen); + full_cmd[0] = '\0'; + strcat(full_cmd, path); + for (i = 1; args[i]; i++) { + strcat(full_cmd, " "); + strcat(full_cmd, args[i]); + } + + /* disable inheritance on local pipe ends*/ + fcntl(pout[1], F_SETFD, FD_CLOEXEC); + fcntl(pin[0], F_SETFD, FD_CLOEXEC); + + sshpid = spawn_child(full_cmd, c_in, c_out, STDERR_FILENO, 0); + free(full_cmd); + } + + if (sshpid == -1) +#else /* !WINDOWS */ if ((sshpid = fork()) == -1) +#endif /* !WINDOWS */ fatal("fork: %s", strerror(errno)); else if (sshpid == 0) { if ((dup2(c_in, STDIN_FILENO) == -1) || @@ -2284,6 +2439,11 @@ main(int argc, char **argv) addargs(&args, "-oClearAllForwardings yes"); ll = SYSLOG_LEVEL_INFO; + +#ifdef WINDOWS + /* prepare for Unicode input */ + _setmode(_fileno(stdin), O_U16TEXT); +#endif infile = stdin; while ((ch = getopt(argc, argv, diff --git a/ssh-add.c b/ssh-add.c index fb9a53e64..a4b591891 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -492,7 +492,12 @@ main(int argc, char **argv) OpenSSL_add_all_algorithms(); #endif +#ifdef WINDOWS + /* Min buffer size allowed in Windows is 2*/ + setvbuf(stdout, NULL, _IOLBF, 2); +#else setvbuf(stdout, NULL, _IOLBF, 0); +#endif /* First, get a connection to the authentication agent. */ switch (r = ssh_get_authentication_socket(&agent_fd)) { diff --git a/ssh-keygen.c b/ssh-keygen.c index 2a7939bfc..0dcfb562b 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1036,6 +1036,12 @@ do_gen_all_hostkeys(struct passwd *pw) } sshkey_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); +#ifdef WINDOWS + /* Windows POSIX adpater does not support fdopen() on open(file)*/ + if ((f = fopen(identity_file, "w")) == NULL) { + error("fopen %s failed: %s", identity_file, strerror(errno)); + /* TODO - set permissions on file */ +#else /* !WINDOWS */ fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { error("Could not save your public key in %s", @@ -1048,6 +1054,7 @@ do_gen_all_hostkeys(struct passwd *pw) if (f == NULL) { error("fdopen %s failed", identity_file); close(fd); +#endif /* !WINDOWS */ sshkey_free(public); first = 0; continue; @@ -1187,6 +1194,10 @@ known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx) static void do_known_hosts(struct passwd *pw, const char *name) { +#ifdef WINDOWS + fatal("Updating known_hosts is not supported in Windows yet."); +#else /* !WINDOWS */ + char *cp, tmp[PATH_MAX], old[PATH_MAX]; int r, fd, oerrno, inplace = 0; struct known_hosts_ctx ctx; @@ -1278,6 +1289,7 @@ do_known_hosts(struct passwd *pw, const char *name) } exit (find_host && !ctx.found_key); +#endif /* !WINDOWS */ } /* @@ -1576,6 +1588,7 @@ load_pkcs11_key(char *path) return private; #else fatal("no pkcs11 support"); + return NULL; #endif /* ENABLE_PKCS11 */ } @@ -2723,11 +2736,18 @@ passphrase_again: printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); +#ifdef WINDOWS + /* Windows POSIX adpater does not support fdopen() on open(file)*/ + if ((f = fopen(identity_file, "w")) == NULL) + fatal("fopen %s failed: %s", identity_file, strerror(errno)); + /* TODO - set permissions on file */ +#else /* !WINDOWS */ if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) fatal("Unable to save public key to %s: %s", identity_file, strerror(errno)); if ((f = fdopen(fd, "w")) == NULL) fatal("fdopen %s failed: %s", identity_file, strerror(errno)); +#endif /* !WINDOWS */ if ((r = sshkey_write(public, f)) != 0) error("write key failed: %s", ssh_err(r)); fprintf(f, " %s\n", comment); diff --git a/ssh.c b/ssh.c index ee0b16dc2..f718e4212 100644 --- a/ssh.c +++ b/ssh.c @@ -1467,6 +1467,14 @@ main(int ac, char **av) static void control_persist_detach(void) { +#ifdef WINDOWS + /* + * This needs some level of support for domain sockets in Windows + * Domain sockets (w/out ancillary data support) can easily be + * implemented using named pipes. + */ + fatal("ControlMaster is not supported in Windows yet"); +#else /* !WINDOWS */ pid_t pid; int devnull, keep_stderr; @@ -1509,6 +1517,7 @@ control_persist_detach(void) } daemon(1, 1); setproctitle("%s [mux]", options.control_path); +#endif /* !WINDOWS */ } /* Do fork() after authentication. Used by "ssh -f" */ diff --git a/sshconnect.c b/sshconnect.c index 96b91ce1a..ac3b40c26 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -105,6 +105,16 @@ static int ssh_proxy_fdpass_connect(const char *host, u_short port, const char *proxy_command) { +#ifdef WINDOWS + fatal("proxy fdpass connect is not supported in Windows"); + /* + * Unix logic relies on passing in ancillary data over domain sockets + * This concept does not exist in Windows. + * Possible implementation in Windows could have proxy_command return + * connection handle through IPC means + */ + return 0; +#else /* !WINDOWS */ char *command_string; int sp[2], sock; pid_t pid; @@ -176,6 +186,7 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, packet_set_connection(sock, sock); return 0; +#endif /* !WINDOWS */ } /* @@ -184,6 +195,10 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, static int ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) { +#ifdef WINDOWS + fatal("Proxy connect is not supported in Windows yet"); + return 0; +#else /* !WINDOWS */ char *command_string; int pin[2], pout[2]; pid_t pid; @@ -253,6 +268,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) /* Indicate OK return */ return 0; +#endif /* !WINDOWS */ } void @@ -1481,6 +1497,10 @@ warn_changed_key(Key *host_key) int ssh_local_cmd(const char *args) { +#ifdef WINDOWS + fatal("executing local command is not supported in Windows yet"); + return 0; +#else /* !WINDOWS */ char *shell; pid_t pid; int status; @@ -1513,6 +1533,7 @@ ssh_local_cmd(const char *args) return (1); return (WEXITSTATUS(status)); +#endif /* !WINDOWS */ } void diff --git a/sshconnect2.c b/sshconnect2.c index 103a2b36a..615a0455b 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -172,9 +172,14 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) compat_cipher_proposal(options.ciphers); myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(options.ciphers); +#ifdef WINDOWS + /* compression not supported in Windows yet */ + myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; +#else /* !WINDOWS */ myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = options.compression ? "zlib@openssh.com,zlib,none" : "none,zlib@openssh.com,zlib"; +#endif /* !WINDOWS */ myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; if (options.hostkeyalgorithms != NULL) { @@ -1573,6 +1578,10 @@ static int ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen) { +#ifdef WINDOWS + fatal("keysign is not supported in Windows yet"); + return -1; +#else /* !WINDOWS */ struct sshbuf *b; struct stat st; pid_t pid; @@ -1682,6 +1691,7 @@ ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, sshbuf_free(b); return 0; +#endif /* !WINDOWS */ } int diff --git a/sshd.c b/sshd.c index 1dc4d182a..16f320602 100644 --- a/sshd.c +++ b/sshd.c @@ -163,7 +163,12 @@ int saved_argc; /* re-exec */ int rexeced_flag = 0; +#ifdef WINDOWS +/* rexec is not applicable in Windows */ +int rexec_flag = 0; +#else /* !WINDOWS */ int rexec_flag = 1; +#endif /* !WINDOWS */ int rexec_argc = 0; char **rexec_argv; @@ -220,7 +225,12 @@ int *startup_pipes = NULL; int startup_pipe; /* in child */ /* variables used for privilege separation */ +#ifdef WINDOWS +/* Windows does not use Unix privilege separation model */ +int use_prevsep = 0; +#else int use_privsep = -1; +#endif struct monitor *pmonitor = NULL; int privsep_is_preauth = 1; @@ -236,6 +246,9 @@ Buffer loginmsg; /* Unprivileged user */ struct passwd *privsep_pw = NULL; +/* is child process - used by Windows implementation*/ +int is_child = 0; + /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); void demote_sensitive_data(void); @@ -521,6 +534,29 @@ reseed_prngs(void) explicit_bzero(rnd, sizeof(rnd)); } +#ifdef WINDOWS +/* + * No-OP defs for preauth routines for Windows + * these should go away once the privilege separation + * related code is refactored to be invoked only when applicable + */ +static void +privsep_preauth_child(void) { + return; +} + +static int +privsep_preauth(Authctxt *authctxt) { + return 0; +} + +static void +privsep_postauth(Authctxt *authctxt) { + return; +} + +#else /* !WINDOWS */ +/* Unix privilege separation routines */ static void privsep_preauth_child(void) { @@ -680,6 +716,8 @@ privsep_postauth(Authctxt *authctxt) packet_set_authenticated(); } +#endif /* !WINDOWS */ + static char * list_hostkey_types(void) { @@ -1046,6 +1084,14 @@ server_listen(void) close(listen_sock); continue; } +#ifdef WINDOWS + /* disable inheritance on listener socket */ + if (fcntl(listen_sock, F_SETFD, FD_CLOEXEC) != 0) { + error("F_SETFD FD_CLOEXEC on listener socket %d failed with %d", listen_sock, errno); + close(listen_sock); + continue; + } +#endif /* WINDOWS */ /* * Set socket options. * Allow local port reuse in TIME_WAIT. @@ -1242,6 +1288,38 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) * parent continues listening. */ platform_pre_fork(); +#ifdef WINDOWS + /* + * fork() repleacement for Windows - + * - Put accepted socket in a env varaibale + * - disable inheritance on listening socket and startup fds + * - Spawn child sshd.exe + */ + { + char* path_utf8 = utf16_to_utf8(GetCommandLineW()); + char fd_handle[30]; /* large enough to hold pointer value in hex */ + + if (path_utf8 == NULL) + fatal("Failed to alloc memory"); + + if (snprintf(fd_handle, sizeof(fd_handle), "%p", sfd_to_handle(*newsock)) == -1 + || SetEnvironmentVariable("SSHD_REMSOC", fd_handle) == FALSE + || snprintf(fd_handle, sizeof(fd_handle), "%p", sfd_to_handle(startup_p[1])) == -1 + || SetEnvironmentVariable("SSHD_STARTUPSOC", fd_handle) == FALSE + || fcntl(startup_p[0], F_SETFD, FD_CLOEXEC) == -1) { + error("unable to set the right environment for child, closing connection "); + close(*newsock); + /* close child end of startup pipe. parent end will automatically be cleaned up on next iteration*/ + close(startup_p[1]); + continue; + } + + pid = spawn_child(path_utf8, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CREATE_NEW_PROCESS_GROUP); + free(path_utf8); + close(*newsock); + } +#else /* !WINDOWS */ + if ((pid = fork()) == 0) { /* * Child. Close the listening and @@ -1265,7 +1343,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) close(config_s[0]); break; } - +#endif /* !WINDOWS */ /* Parent. Stay in the loop. */ platform_post_fork_parent(pid); if (pid < 0) @@ -1634,6 +1712,7 @@ main(int ac, char **av) #endif ); +#ifndef WINDOWS /* not applicable in Windows */ /* Store privilege separation user for later use if required. */ if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { if (use_privsep || options.kerberos_authentication) @@ -1647,6 +1726,7 @@ main(int ac, char **av) privsep_pw->pw_passwd = xstrdup("*"); } endpwent(); +#endif /* !WINDOWS */ /* load host keys */ sensitive_data.host_keys = xcalloc(options.num_host_key_files, @@ -1664,7 +1744,9 @@ main(int ac, char **av) error("Could not connect to agent \"%s\": %s", options.host_key_agent, ssh_err(r)); } - +#ifdef WINDOWS /* Windows version always needs and has agent running */ + have_agent = 1; +#endif for (i = 0; i < options.num_host_key_files; i++) { if (options.host_key_files[i] == NULL) continue; @@ -1840,6 +1922,10 @@ main(int ac, char **av) server_accept_inetd(&sock_in, &sock_out); } else { platform_pre_listen(); +#ifdef WINDOWS + /* For Windows child sshd, skip listener */ + if (is_child == 0) +#endif /* WINDOWS */ server_listen(); signal(SIGHUP, sighup_handler); @@ -1863,6 +1949,27 @@ main(int ac, char **av) } } +#ifdef WINDOWS + /* Windows - for sshd child, pick up the accepted socket*/ + if (is_child) { + char *stopstring; + DWORD_PTR handle; + + handle = strtol(getenv("SSHD_REMSOC"), &stopstring, 16); + SetEnvironmentVariable("SSHD_REMSOC", NULL); + debug("child socket: %d", handle); + sock_in = sock_out = newsock = w32_allocate_fd_for_handle((HANDLE)handle, TRUE); + fcntl(newsock, F_SETFD, FD_CLOEXEC); + + handle = strtol(getenv("SSHD_STARTUPSOC"), &stopstring, 16); + SetEnvironmentVariable("SSHD_STARTUPSOC", NULL); + debug("child startup_pipe: %d", handle); + startup_pipe = w32_allocate_fd_for_handle((HANDLE)handle, FALSE); + fcntl(startup_pipe, F_SETFD, FD_CLOEXEC); + } + else /* Windows and Unix sshd parent */ +#endif /* WINDOWS */ + /* Accept a connection and return in a forked child */ server_accept_loop(&sock_in, &sock_out, &newsock, config_s); diff --git a/sshpty.c b/sshpty.c index fe2fb5aa2..3d6e2b118 100644 --- a/sshpty.c +++ b/sshpty.c @@ -53,6 +53,56 @@ # endif #endif +#ifdef WINDOWS +/* + * Windows versions of pty_*. Some of them are NO-OPs and should go away when + * pty logic is refactored and abstracted out + * + */ +int +pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) +{ + /* + * Simple console screen implementation in Win32 to give a Unix like pty for interactive sessions + */ + *ttyfd = 0; + *ptyfd = 0; + strlcpy(namebuf, "console", namebuflen); + return 1; +} + +void +pty_release(const char *tty) { + /* NO-OP */ +} + +void +pty_make_controlling_tty(int *ttyfd, const char *tty) { + /* NO-OP */ +} + +void +pty_change_window_size(int ptyfd, u_int row, u_int col, + u_int xpixel, u_int ypixel) { + COORD coord; + coord.X = col; + coord.Y = 9999; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord); +} + + +void +pty_setowner(struct passwd *pw, const char *tty) { + /* NO-OP */ +} + +void +disconnect_controlling_tty(void) { + /* NO-OP */ +} + +#else + /* * Allocates and opens a pty. Returns 0 if no pty could be allocated, or * nonzero if a pty was successfully allocated. On success, open file @@ -252,3 +302,4 @@ disconnect_controlling_tty(void) } #endif /* TIOCNOTTY */ } +#endif diff --git a/sshtty.c b/sshtty.c index d214ce3bb..b971bbc54 100644 --- a/sshtty.c +++ b/sshtty.c @@ -47,6 +47,34 @@ static struct termios _saved_tio; static int _in_raw_mode = 0; +#ifdef WINDOWS +/* + * TTY raw mode routines for Windows + */ + +int ConInit(DWORD OutputHandle, BOOL fSmartInit); +int ConUnInit(void); + +struct termios term_settings; + +/* TODO - clean this up for Windows, ConInit should return previous terminal settings that need to be stored in term_settings*/ + +struct termios * + get_saved_tio(void) { + memset(&term_settings, 0, sizeof(term_settings)); + return &term_settings; +} + +void +leave_raw_mode(int quiet) { + ConUnInit(); +} + +void +enter_raw_mode(int quiet) { + ConInit(STD_OUTPUT_HANDLE, TRUE); +} +#else /* !WINDOWS */ struct termios * get_saved_tio(void) { @@ -94,3 +122,4 @@ enter_raw_mode(int quiet) } else _in_raw_mode = 1; } +#endif /* !WINDOWS */ \ No newline at end of file diff --git a/utf8.c b/utf8.c index 87fa9e89a..00a0a73ec 100644 --- a/utf8.c +++ b/utf8.c @@ -57,10 +57,16 @@ static int vasnmprintf(char **, size_t, int *, const char *, va_list); static int dangerous_locale(void) { +#ifdef WINDOWS + wchar_t loc[LOCALE_NAME_MAX_LENGTH]; + GetSystemDefaultLocaleName(loc, LOCALE_NAME_MAX_LENGTH); + return wcscmp(loc, L"US-ASCII") && wcscmp(loc, L"UTF-8"); +#else /* !WINDOWS */ char *loc; loc = nl_langinfo(CODESET); return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8"); +#endif /* !WINDOWS */ } static int