diff --git a/auth-passwd.c b/auth-passwd.c index 3b81c2d6..f64730fc 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -54,6 +54,7 @@ #include "hostfile.h" #include "auth.h" #include "auth-options.h" +#include "authfd.h" extern Buffer loginmsg; extern ServerOptions options; @@ -225,38 +226,36 @@ sys_auth_passwd(Authctxt *authctxt, const char *password) #elif defined(WINDOWS) /* -* Authenticate on Windows - Pass creds to ssh-agent and retrieve token +* Authenticate on Windows - Pass credentials 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; + int r; 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; - } + fatal("%s: out of memory", __func__); - - if (blob) - free(blob); + if (sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE) != 0 || + sshbuf_put_cstring(msg, PASSWD_AUTH_REQUEST) != 0 || + sshbuf_put_cstring(msg, authctxt->pw->pw_name) != 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->user); + r = 0; + goto done; + } + authctxt->methoddata = (void*)(INT_PTR)token; + r = 1; +done: if (msg) sshbuf_free(msg); - - authctxt->methoddata = (void*)(INT_PTR)token; - - return 1; + return r; } #endif /* WINDOWS */ diff --git a/auth2-pubkey.c b/auth2-pubkey.c index a5a5c273..cd8dd1b7 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.61 2016/12/30 22:08:02 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.62 2017/01/30 01:03:00 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -68,6 +68,7 @@ #include "ssherr.h" #include "channels.h" /* XXX for session.h */ #include "session.h" /* XXX for child_set_env(); refactor? */ +#include "authfd.h" /* import */ extern ServerOptions options; @@ -189,21 +190,21 @@ userauth_pubkey(Authctxt *authctxt) 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); + fatal("%s: out of memory", __func__); + if ((r = sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE)) != 0 || + (r = sshbuf_put_cstring(msg, PUBKEY_AUTH_REQUEST)) != 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->user); break; } - debug3("auth agent authenticated %s", authctxt->pw->pw_name); + debug3("auth agent authenticated %s", authctxt->user); break; } @@ -620,9 +621,12 @@ process_principals(FILE *f, char *file, struct passwd *pw, { char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; u_long linenum = 0; - u_int i; + u_int i, found_principal = 0; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { + /* Always consume entire input */ + if (found_principal) + continue; /* Skip leading whitespace. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; @@ -655,11 +659,12 @@ process_principals(FILE *f, char *file, struct passwd *pw, if (auth_parse_options(pw, line_opts, file, linenum) != 1) continue; - return 1; + found_principal = 1; + continue; } } } - return 0; + return found_principal; } static int @@ -827,6 +832,9 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) char *cp, *key_options = NULL, *fp = NULL; const char *reason = NULL; + /* Always consume entrire file */ + if (found_key) + continue; if (found != NULL) key_free(found); found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); @@ -913,7 +921,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) file, linenum, key_type(found), fp); free(fp); found_key = 1; - break; + continue; } } if (found != NULL) diff --git a/auth2.c b/auth2.c index 9108b861..97dd2ef0 100644 --- a/auth2.c +++ b/auth2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2.c,v 1.136 2016/05/02 08:49:03 djm Exp $ */ +/* $OpenBSD: auth2.c,v 1.137 2017/02/03 23:05:57 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -212,6 +212,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt) static int input_userauth_request(int type, u_int32_t seq, void *ctxt) { + struct ssh *ssh = active_state; /* XXX */ Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; @@ -235,9 +236,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) authctxt->user = xstrdup(user); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; - debug2("input_userauth_request: setting up authctxt for %s", user); + debug2("%s: setting up authctxt for %s", + __func__, user); } else { - logit("input_userauth_request: invalid user %s", user); + /* Invalid user, fake password information */ authctxt->pw = fakepw(); #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_INVALID_USER)); @@ -247,6 +249,8 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif + ssh_packet_set_log_preamble(ssh, "%suser %s", + authctxt->valid ? "authenticating " : "invalid ", user); setproctitle("%s%s", authctxt->valid ? user : "unknown", use_privsep ? " [net]" : ""); authctxt->service = xstrdup(service); @@ -292,6 +296,7 @@ void userauth_finish(Authctxt *authctxt, int authenticated, const char *method, const char *submethod) { + struct ssh *ssh = active_state; /* XXX */ char *methods; int partial = 0; @@ -353,6 +358,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, packet_write_wait(); /* now we can break out */ authctxt->success = 1; + ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); } else { /* Allow initial try of "none" auth without failure penalty */ diff --git a/authfd.c b/authfd.c index 6d275454..63614c94 100644 --- a/authfd.c +++ b/authfd.c @@ -97,35 +97,39 @@ ssh_get_authentication_socket(int *fdp) #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; + DWORD connection_attempts = 0; HANDLE h; - RegOpenKeyExW(HKEY_LOCAL_MACHINE, SSH_AGENT_REG_ROOT, 0, KEY_QUERY_VALUE, &agent_root); + 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); + RegQueryValueEx(agent_root, "ProcessId", 0, + NULL, (LPBYTE)&agent_pid, &tmp_size); RegCloseKey(agent_root); } do { h = CreateFileW(SSH_AGENT_PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (h != INVALID_HANDLE_VALUE || GetLastError() != ERROR_PIPE_BUSY) + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (h != INVALID_HANDLE_VALUE || GetLastError() != ERROR_PIPE_BUSY || + ++connection_attempts > 10) break; Sleep(100); } while(1); if (h == INVALID_HANDLE_VALUE) { - debug("ssh_get_authentication_socket - CreateFileW failed error %d", GetLastError()); + debug("ssh_get_authentication_socket - CreateFileW failed error %d", + GetLastError()); return SSH_ERR_AGENT_NOT_PRESENT; } /* - * ensure that connected server pid matches published pid. this provides service side - * auth and prevents mitm + * 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)) { + if (!GetNamedPipeServerProcessId(h, &pipe_server_pid) || + (agent_pid != pipe_server_pid)) { debug("agent pid mismatch"); CloseHandle(h); return SSH_ERR_AGENT_COMMUNICATION; diff --git a/authfd.h b/authfd.h index 4b417e3f..46814791 100644 --- a/authfd.h +++ b/authfd.h @@ -89,4 +89,14 @@ int ssh_agent_sign(int sock, struct sshkey *key, #define SSH_AGENT_RSA_SHA2_256 0x02 #define SSH_AGENT_RSA_SHA2_512 0x04 +/* +* Following are used in Windows implementation +* ssh-agent in Windows also serves user authentication +*/ +#define SSH_AGENT_AUTHENTICATE 200 +#define PUBKEY_AUTH_REQUEST "pubkey" +#define PASSWD_AUTH_REQUEST "password" +#define SSH_AGENT_REG_ROOT L"SOFTWARE\\SSH\\Agent" +#define SSH_AGENT_PIPE_NAME L"\\\\.\\pipe\\ssh-agent" + #endif /* AUTHFD_H */ diff --git a/channels.c b/channels.c index ef4018b0..ddd2b24a 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.356 2016/10/18 17:32:54 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.357 2017/02/01 02:59:09 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -3067,7 +3067,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt) } packet_check_eom(); c = channel_connect_to_port(host, host_port, - "connected socket", originator_string); + "connected socket", originator_string, NULL, NULL); free(originator_string); free(host); if (c == NULL) { @@ -4028,9 +4028,13 @@ channel_connect_ctx_free(struct channel_connect *cctx) memset(cctx, 0, sizeof(*cctx)); } -/* Return CONNECTING channel to remote host:port or local socket path */ +/* + * Return CONNECTING channel to remote host:port or local socket path, + * passing back the failure reason if appropriate. + */ static Channel * -connect_to(const char *name, int port, char *ctype, char *rname) +connect_to_reason(const char *name, int port, char *ctype, char *rname, + int *reason, const char **errmsg) { struct addrinfo hints; int gaierr; @@ -4071,7 +4075,12 @@ connect_to(const char *name, int port, char *ctype, char *rname) hints.ai_family = IPv4or6; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", port); - if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) != 0) { + if ((gaierr = getaddrinfo(name, strport, &hints, &cctx.aitop)) + != 0) { + if (errmsg != NULL) + *errmsg = ssh_gai_strerror(gaierr); + if (reason != NULL) + *reason = SSH2_OPEN_CONNECT_FAILED; error("connect_to %.100s: unknown host (%s)", name, ssh_gai_strerror(gaierr)); return NULL; @@ -4094,6 +4103,13 @@ connect_to(const char *name, int port, char *ctype, char *rname) return c; } +/* Return CONNECTING channel to remote host:port or local socket path */ +static Channel * +connect_to(const char *name, int port, char *ctype, char *rname) +{ + return connect_to_reason(name, port, ctype, rname, NULL, NULL); +} + /* * returns either the newly connected channel or the downstream channel * that needs to deal with this connection. @@ -4138,7 +4154,8 @@ channel_connect_by_listen_path(const char *path, char *ctype, char *rname) /* Check if connecting to that port is permitted and connect. */ Channel * -channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname) +channel_connect_to_port(const char *host, u_short port, char *ctype, + char *rname, int *reason, const char **errmsg) { int i, permit, permit_adm = 1; @@ -4163,9 +4180,11 @@ channel_connect_to_port(const char *host, u_short port, char *ctype, char *rname if (!permit || !permit_adm) { logit("Received request to connect to host %.100s port %d, " "but the request was denied.", host, port); + if (reason != NULL) + *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; return NULL; } - return connect_to(host, port, ctype, rname); + return connect_to_reason(host, port, ctype, rname, reason, errmsg); } /* Check if connecting to that path is permitted and connect. */ diff --git a/channels.h b/channels.h index 09c3c365..ce43236d 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.120 2016/10/18 17:32:54 dtucker Exp $ */ +/* $OpenBSD: channels.h,v 1.121 2017/02/01 02:59:09 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -275,7 +275,8 @@ void channel_update_permitted_opens(int, int); void channel_clear_permitted_opens(void); void channel_clear_adm_permitted_opens(void); void channel_print_adm_permitted_opens(void); -Channel *channel_connect_to_port(const char *, u_short, char *, char *); +Channel *channel_connect_to_port(const char *, u_short, char *, char *, int *, + const char **); Channel *channel_connect_to_path(const char *, char *, char *); Channel *channel_connect_stdio_fwd(const char*, u_short, int, int); Channel *channel_connect_by_listen_address(const char *, u_short, diff --git a/clientloop.c b/clientloop.c index 5bec8c0f..5a213878 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.289 2016/09/30 09:19:13 markus Exp $ */ +/* $OpenBSD: clientloop.c,v 1.290 2017/01/29 21:35:23 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -991,7 +991,7 @@ process_cmdline(void) CHANNEL_CANCEL_PORT_STATIC, &options.fwd_opts) > 0; if (!ok) { - logit("Unkown port forwarding."); + logit("Unknown port forwarding."); goto out; } logit("Canceled forwarding."); diff --git a/compat.c b/compat.c index 69a104fb..1e80cfa9 100644 --- a/compat.c +++ b/compat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: compat.c,v 1.99 2016/05/24 02:31:57 dtucker Exp $ */ +/* $OpenBSD: compat.c,v 1.100 2017/02/03 23:01:19 djm Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -37,6 +37,7 @@ #include "compat.h" #include "log.h" #include "match.h" +#include "kex.h" int compat13 = 0; int compat20 = 0; @@ -250,42 +251,14 @@ proto_spec(const char *spec) return ret; } -/* - * Filters a proposal string, excluding any algorithm matching the 'filter' - * pattern list. - */ -static char * -filter_proposal(char *proposal, const char *filter) -{ - Buffer b; - char *orig_prop, *fix_prop; - char *cp, *tmp; - - buffer_init(&b); - tmp = orig_prop = xstrdup(proposal); - while ((cp = strsep(&tmp, ",")) != NULL) { - if (match_pattern_list(cp, filter, 0) != 1) { - if (buffer_len(&b) > 0) - buffer_append(&b, ",", 1); - buffer_append(&b, cp, strlen(cp)); - } else - debug2("Compat: skipping algorithm \"%s\"", cp); - } - buffer_append(&b, "\0", 1); - fix_prop = xstrdup((char *)buffer_ptr(&b)); - buffer_free(&b); - free(orig_prop); - - return fix_prop; -} - char * compat_cipher_proposal(char *cipher_prop) { if (!(datafellows & SSH_BUG_BIGENDIANAES)) return cipher_prop; debug2("%s: original cipher proposal: %s", __func__, cipher_prop); - cipher_prop = filter_proposal(cipher_prop, "aes*"); + if ((cipher_prop = match_filter_list(cipher_prop, "aes*")) == NULL) + fatal("match_filter_list failed"); debug2("%s: compat cipher proposal: %s", __func__, cipher_prop); if (*cipher_prop == '\0') fatal("No supported ciphers found"); @@ -298,7 +271,8 @@ compat_pkalg_proposal(char *pkalg_prop) if (!(datafellows & SSH_BUG_RSASIGMD5)) return pkalg_prop; debug2("%s: original public key proposal: %s", __func__, pkalg_prop); - pkalg_prop = filter_proposal(pkalg_prop, "ssh-rsa"); + if ((pkalg_prop = match_filter_list(pkalg_prop, "ssh-rsa")) == NULL) + fatal("match_filter_list failed"); debug2("%s: compat public key proposal: %s", __func__, pkalg_prop); if (*pkalg_prop == '\0') fatal("No supported PK algorithms found"); @@ -312,10 +286,14 @@ compat_kex_proposal(char *p) return p; debug2("%s: original KEX proposal: %s", __func__, p); if ((datafellows & SSH_BUG_CURVE25519PAD) != 0) - p = filter_proposal(p, "curve25519-sha256@libssh.org"); + if ((p = match_filter_list(p, + "curve25519-sha256@libssh.org")) == NULL) + fatal("match_filter_list failed"); if ((datafellows & SSH_OLD_DHGEX) != 0) { - p = filter_proposal(p, "diffie-hellman-group-exchange-sha256"); - p = filter_proposal(p, "diffie-hellman-group-exchange-sha1"); + if ((p = match_filter_list(p, + "diffie-hellman-group-exchange-sha256," + "diffie-hellman-group-exchange-sha1")) == NULL) + fatal("match_filter_list failed"); } debug2("%s: compat KEX proposal: %s", __func__, p); if (*p == '\0') diff --git a/configure.ac b/configure.ac index eb9f45dc..972addfe 100644 --- a/configure.ac +++ b/configure.ac @@ -740,6 +740,9 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) use_pie=auto check_for_libcrypt_later=1 check_for_openpty_ctty_bug=1 + dnl Target SUSv3/POSIX.1-2001 plus BSD specifics. + dnl _DEFAULT_SOURCE is the new name for _BSD_SOURCE + CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE" AC_DEFINE([PAM_TTY_KLUDGE], [1], [Work around problematic Linux PAM modules handling of PAM_TTY]) AC_DEFINE([LOCKED_PASSWD_PREFIX], ["!"], @@ -1471,36 +1474,47 @@ AC_ARG_WITH([skey], LDNS_MSG="no" AC_ARG_WITH(ldns, [ --with-ldns[[=PATH]] Use ldns for DNSSEC support (optionally in PATH)], - [ - if test "x$withval" != "xno" ; then - - if test "x$withval" != "xyes" ; then - CPPFLAGS="$CPPFLAGS -I${withval}/include" - LDFLAGS="$LDFLAGS -L${withval}/lib" - fi - - AC_DEFINE(HAVE_LDNS, 1, [Define if you want ldns support]) - LIBS="-lldns $LIBS" - LDNS_MSG="yes" + [ + ldns="" + if test "x$withval" = "xyes" ; then + AC_PATH_TOOL([LDNSCONFIG], [ldns-config], [no]) + if test "x$PKGCONFIG" = "xno"; then + CPPFLAGS="$CPPFLAGS -I${withval}/include" + LDFLAGS="$LDFLAGS -L${withval}/lib" + LIBS="-lldns $LIBS" + ldns=yes + else + LIBS="$LIBS `$LDNSCONFIG --libs`" + CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`" + fi + elif test "x$withval" != "xno" ; then + CPPFLAGS="$CPPFLAGS -I${withval}/include" + LDFLAGS="$LDFLAGS -L${withval}/lib" + LIBS="-lldns $LIBS" + ldns=yes + fi - AC_MSG_CHECKING([for ldns support]) - AC_LINK_IFELSE( - [AC_LANG_SOURCE([[ + # Verify that it works. + if test "x$ldns" = "xyes" ; then + AC_DEFINE(HAVE_LDNS, 1, [Define if you want ldns support]) + LDNS_MSG="yes" + AC_MSG_CHECKING([for ldns support]) + AC_LINK_IFELSE( + [AC_LANG_SOURCE([[ #include #include #include #include int main() { ldns_status status = ldns_verify_trusted(NULL, NULL, NULL, NULL); status=LDNS_STATUS_OK; exit(0); } - ]]) - ], - [AC_MSG_RESULT(yes)], + ]]) + ], + [AC_MSG_RESULT(yes)], [ AC_MSG_RESULT(no) AC_MSG_ERROR([** Incomplete or missing ldns libraries.]) ]) - fi - ] -) + fi +]) # Check whether user wants libedit support LIBEDIT_MSG="no" @@ -1771,11 +1785,8 @@ AC_CHECK_FUNCS([ \ warn \ ]) -dnl Wide character support. Linux man page says it needs _XOPEN_SOURCE. -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -D_XOPEN_SOURCE" +dnl Wide character support. AC_CHECK_FUNCS([mblen mbtowc nl_langinfo wcwidth]) -CFLAGS="$saved_CFLAGS" TEST_SSH_UTF8=${TEST_SSH_UTF8:=yes} AC_MSG_CHECKING([for utf8 locale support]) @@ -5083,6 +5094,7 @@ echo " Smartcard support: $SCARD_MSG" echo " S/KEY support: $SKEY_MSG" echo " MD5 password support: $MD5_MSG" echo " libedit support: $LIBEDIT_MSG" +echo " libldns support: $LDNS_MSG" echo " Solaris process contract support: $SPC_MSG" echo " Solaris project support: $SP_MSG" echo " Solaris privilege support: $SPP_MSG" diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index c7313058..3d860fea 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh", "ssh.vcxproj", "{74E69D5E-A1EF-46EA-9173-19A412774104}" ProjectSection(ProjectDependencies) = postProject @@ -68,6 +68,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-shellhost", "ssh-shellhost.vcxproj", "{C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}" ProjectSection(ProjectDependencies) = postProject {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-agent", "ssh-agent.vcxproj", "{F6644EC5-D6B6-42A1-828C-75E2977470E0}" diff --git a/contrib/win32/openssh/appveyor.psm1 b/contrib/win32/openssh/appveyor.psm1 index f248fa8c..8d6eb7e1 100644 --- a/contrib/win32/openssh/appveyor.psm1 +++ b/contrib/win32/openssh/appveyor.psm1 @@ -3,7 +3,6 @@ Import-Module $PSScriptRoot\build.psm1 -Force -DisableNameChecking $repoRoot = Get-RepositoryRoot $script:logFile = join-path $repoRoot.FullName "appveyor.log" $script:messageFile = join-path $repoRoot.FullName "BuildMessage.log" -$testfailed = $false <# Called by Write-BuildMsg to write to the build log, if it exists. @@ -234,13 +233,20 @@ function Download-PSCoreMSI .SYNOPSIS This function installs the tools required by our tests 1) Pester for running the tests - 2) sysinternals required by the tests on windows. + 2) sysinternals required by the tests on windows. #> function Install-TestDependencies { [CmdletBinding()] param () - + + # Install chocolatey + if(-not (Get-Command "choco" -ErrorAction SilentlyContinue)) + { + Write-Log -Message "Chocolatey not present. Installing chocolatey." + Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $script:logFile + } + $isModuleAvailable = Get-Module 'Pester' -ListAvailable if (-not ($isModuleAvailable)) { @@ -360,18 +366,18 @@ function Build-Win32OpenSSHPackage $folderName = $NativeHostArch if($NativeHostArch -ieq 'x86') { - $folderName = "Win32" + $folderName = "Win32" } } else { if($platform -ieq "AMD64") { - $folderName = "x64" + $folderName = "x64" } else { - $folderName = "Win32" + $folderName = "Win32" } } @@ -430,7 +436,7 @@ function Build-Win32OpenSSHPackage } Add-Type -assemblyname System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::CreateFromDirectory($OpenSSHDir, $package) + [System.IO.Compression.ZipFile]::CreateFromDirectory($OpenSSHDir, $package) } <# @@ -494,43 +500,15 @@ function Deploy-OpenSSHTests } - [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot - + [System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot + #copy all pester tests $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "regress\pesterTests" - Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Include *.ps1,*.psm1 -Force -ErrorAction Stop - - $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" - Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Exclude ssh-agent.exe, sshd.exe -Force -ErrorAction Stop - - - $sshdConfigFile = "$OpenSSHTestDir\sshd_config" - if (-not (Test-Path -Path $sshdConfigFile -PathType Leaf)) - { - Write-BuildMessage "Installation dependencies: $OpenSSHTestDir\sshd_config is missing in the folder" -Category Error - throw "$OpenSSHTestDir\sshd_config is missing in the folder" - } - - if ($env:DebugMode) - { - $strToReplace = "#LogLevel INFO" - (Get-Content $sshdConfigFile).Replace($strToReplace,"LogLevel Debug3") | Set-Content $sshdConfigFile - } - if(-not ($env:psPath)) - { - $psCorePath = GetLocalPSCorePath - Set-BuildVariable -Name psPath -Value $psCorePath - } - - $strToReplace = "Subsystem sftp sftp-server.exe" - if($env:psPath) - { - $strNewsubSystem = @" -Subsystem sftp sftp-server.exe -Subsystem powershell $env:psPath -"@ - } - - (Get-Content $sshdConfigFile).Replace($strToReplace, $strNewsubSystem) | Set-Content $sshdConfigFile + Copy-Item -Path "$sourceDir\*" -Destination $OpenSSHTestDir -Include *.ps1,*.psm1, sshd_config -Force -ErrorAction Stop + #copy all unit tests. + $sourceDir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" + Copy-Item -Path "$sourceDir\unittest-*" -Destination $OpenSSHTestDir -Force -ErrorAction Stop + #restart the service to use the test copy of sshd_config + Restart-Service sshd } @@ -691,7 +669,7 @@ function Run-OpenSSHUnitTest Remove-Item -Path $unitTestOutputFile -Force -ErrorAction SilentlyContinue } - $unitTestFiles = Get-ChildItem -Path "$testRoot\unittest*.exe" -Exclude unittest-kex.exe + $unitTestFiles = Get-ChildItem -Path "$testRoot\unittest*.exe" -Exclude unittest-kex.exe,unittest-hostkeys.exe $testfailed = $false if ($unitTestFiles -ne $null) { diff --git a/contrib/win32/openssh/build.psm1 b/contrib/win32/openssh/build.psm1 index ba84d20d..0501d13b 100644 --- a/contrib/win32/openssh/build.psm1 +++ b/contrib/win32/openssh/build.psm1 @@ -152,17 +152,6 @@ function Start-SSHBootstrap { Write-BuildMsg -AsInfo -Message "Chocolatey not present. Installing chocolatey." -Silent:$silent Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 2>&1 >> $script:BuildLogFile - - if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower()))) - { - Write-BuildMsg -AsVerbose -Message "Adding $chocolateyPath to Path environment variable" -Silent:$silent - $newMachineEnvironmentPath += ";$chocolateyPath" - $env:Path += ";$chocolateyPath" - } - else - { - Write-BuildMsg -AsVerbose -Message "$chocolateyPath already present in Path environment variable" -Silent:$silent - } } # Add git\cmd to the path @@ -231,7 +220,7 @@ function Start-SSHBootstrap # Install Windows 8.1 SDK $packageName = "windows-sdk-8.1" - $sdkPath = "C:\Program Files (x86)\Windows Kits\8.1\bin\x86\register_app.vbs" + $sdkPath = "${env:ProgramFiles(x86)}\Windows Kits\8.1\bin\x86\register_app.vbs" if (-not (Test-Path -Path $sdkPath)) { @@ -264,7 +253,7 @@ function Start-SSHBootstrap Write-BuildMsg -AsVerbose -Message "vcPath: $script:vcPath" -Silent:$silent if ((Test-Path -Path "$script:vcPath\vcvarsall.bat") -eq $false) { - Write-BuildMsg -AsError -ErrorAction Stop -Message "Could not find Visual Studio vcvarsall.bat at" + $script:vcPath + Write-BuildMsg -AsError -ErrorAction Stop -Message "Could not find Visual Studio vcvarsall.bat at$script:vcPath, which means some required develop kits are missing on the machine." } } diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index edcd5610..b4d48783 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1673,19 +1673,18 @@ #define HAVE_DECL_HOWMANY 0 #define HAVE_STRTOULL 1 #define HAVE_USLEEP 1 +#define HAVE_EVP_RIPEMD160 1 #if defined ( WIN32 ) #define __func__ __FUNCTION__ #endif -#define PATH_MAX MAX_PATH +/* Windows specific macro added to workaround mysignal implementaion in bsd-misc.c */ +#define HAVE_MYSIGNAL 1 -//#define IN_LOOPBACKNET INADDR_LOOPBACK +#define PATH_MAX MAX_PATH #define S_IFIFO 0x1000 -//#define SHUT_RDWR 2 -//#define SHUT_WR 1 -//#define SHUT_RD 0 #define HAVE_EXPLICIT_BZERO diff --git a/contrib/win32/openssh/config.vcxproj b/contrib/win32/openssh/config.vcxproj index c171a31d..45d6ca4a 100644 --- a/contrib/win32/openssh/config.vcxproj +++ b/contrib/win32/openssh/config.vcxproj @@ -201,4 +201,7 @@ + + + \ No newline at end of file diff --git a/contrib/win32/openssh/install-sshd.ps1 b/contrib/win32/openssh/install-sshd.ps1 index d16a63ee..f0f2b780 100644 --- a/contrib/win32/openssh/install-sshd.ps1 +++ b/contrib/win32/openssh/install-sshd.ps1 @@ -38,7 +38,10 @@ cd $scriptdir cmd.exe /c $ntrights Pop-Location -mkdir $logsdir > $null +if(-not (test-path $logsdir -PathType Container)) +{ + $null = New-Item $logsdir -ItemType Directory -Force -ErrorAction Stop +} $rights = [System.Security.AccessControl.FileSystemRights]"Read, Write" $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($account, $rights, "ContainerInherit,ObjectInherit", "None", "Allow") $acl = Get-Acl -Path $logsdir diff --git a/contrib/win32/openssh/ssh-agent.vcxproj b/contrib/win32/openssh/ssh-agent.vcxproj index 682b169d..d5f3b458 100644 --- a/contrib/win32/openssh/ssh-agent.vcxproj +++ b/contrib/win32/openssh/ssh-agent.vcxproj @@ -202,6 +202,7 @@ + @@ -212,8 +213,9 @@ - - + + + diff --git a/contrib/win32/openssh/ssh-shellhost.vcxproj b/contrib/win32/openssh/ssh-shellhost.vcxproj index 5c8ac5f8..d4316184 100644 --- a/contrib/win32/openssh/ssh-shellhost.vcxproj +++ b/contrib/win32/openssh/ssh-shellhost.vcxproj @@ -21,6 +21,7 @@ + @@ -113,7 +114,7 @@ Console true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) @@ -133,7 +134,7 @@ Console true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) @@ -156,7 +157,7 @@ true true true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) true No @@ -181,9 +182,10 @@ true true true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true No + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) diff --git a/contrib/win32/openssh/sshd.vcxproj b/contrib/win32/openssh/sshd.vcxproj index a7e8be48..80e6ae46 100644 --- a/contrib/win32/openssh/sshd.vcxproj +++ b/contrib/win32/openssh/sshd.vcxproj @@ -248,6 +248,7 @@ + diff --git a/contrib/win32/openssh/sshd.vcxproj.filters b/contrib/win32/openssh/sshd.vcxproj.filters index cd2c9120..96135ead 100644 --- a/contrib/win32/openssh/sshd.vcxproj.filters +++ b/contrib/win32/openssh/sshd.vcxproj.filters @@ -150,6 +150,9 @@ Source Files + + Source Files + diff --git a/contrib/win32/openssh/version.rc b/contrib/win32/openssh/version.rc index 00039b18..28e97ef7 100644 Binary files a/contrib/win32/openssh/version.rc and b/contrib/win32/openssh/version.rc differ diff --git a/contrib/win32/openssh/win32iocompat.vcxproj b/contrib/win32/openssh/win32iocompat.vcxproj index 741649c2..6039af70 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj +++ b/contrib/win32/openssh/win32iocompat.vcxproj @@ -159,6 +159,7 @@ + diff --git a/contrib/win32/openssh/win32iocompat.vcxproj.filters b/contrib/win32/openssh/win32iocompat.vcxproj.filters index ac34a356..07a88fa4 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj.filters +++ b/contrib/win32/openssh/win32iocompat.vcxproj.filters @@ -18,6 +18,7 @@ + diff --git a/contrib/win32/win32compat/ansiprsr.c b/contrib/win32/win32compat/ansiprsr.c index 2e5beb20..f2e99bc6 100644 --- a/contrib/win32/win32compat/ansiprsr.c +++ b/contrib/win32/win32compat/ansiprsr.c @@ -4,7 +4,7 @@ * Copyright (c) 2015 Microsoft Corp. * All rights reserved * - * Microsoft openssh win32 port + * ANSI Parser to 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 @@ -27,18 +27,11 @@ * (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" @@ -48,305 +41,282 @@ #define TS_IS 0 #define TS_SEND 1 -// items used from other modules +/* items used from other modules */ TelParams Parameters; extern int ScreenX; extern int ScreenY; extern int ScrollTop; extern int ScrollBottom; - extern BOOL bAnsiParsing; -// 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; - +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 = TERM_ANSI; -// 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}; +/* + * 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 bMode = 0; +int fcompletion = 1; int bExtMode = 0; -int bCS0 = 0; +int bCS0 = 0; int bCS1 = 0; -int bBkMode = 0; -int bCharMode = 0; +int bBkMode = 0; +int bCharMode = 0; int ReportedX = 0; int ReportedY = 0; +int VTMode = 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]; +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_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_LNM 0x0200 #define MODE_IRM_INSERT 0x0400 -int VTMode = 0; - #define MODE_CURSORAPP 0x0001 #define MODE_ANSIVT52 0x0002 -#define MODE_COL132 0x0004 +#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_LNM 0x0200 -char *GetTerminalId() +char * +GetTerminalId() { return TERMINAL_ID; } -char * GetStatusReport() +char * +GetStatusReport() { return STATUS_REPORT; } -char * GetCursorPositionReport() +char * +GetCursorPositionReport() { - DWORD wr = 0; - DWORD out = 0; + DWORD wr = 0; + DWORD out = 0; - out = _snprintf_s(cursor_report, sizeof(cursor_report), _TRUNCATE, - CURSOR_REPORT_FORMAT_STRING, ConGetCursorY() + 1, ConGetCursorX() + 1); + out = _snprintf_s(cursor_report, sizeof(cursor_report), _TRUNCATE, + CURSOR_REPORT_FORMAT_STRING, ConGetCursorY() + 1, ConGetCursorX() + 1); + if (out > 0) + return cursor_report; - if (out > 0) { - return cursor_report; - } - - return NULL; + return NULL; } -void BufConvertToG2(char * pszBuffer, int length) +void +BufConvertToG2(char * pszBuffer, int length) { - int i; - - for (i=0;i= (ConWindowSizeY()-1)) - { - ConScrollDown(ScrollTop,ScrollBottom); - ConMoveCursorPosition(-ConGetCursorX(),0); + if (ConGetCursorY() >= (ConWindowSizeY() - 1)) { + ConScrollDown(ScrollTop, ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(), 0); } else - ConMoveCursorPosition(-ConGetCursorX(),1); + ConMoveCursorPosition(-ConGetCursorX(), 1); + bAtEOLN = FALSE; } -unsigned char* ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char **respbuf, size_t *resplen) +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; + if (!fcompletion) { + if (pszBuffer < pszBufferEnd - 1) { + unsigned char * pszCurrent = pszBuffer + 1; unsigned char * pszNewCurrent = pszCurrent; if (term_mode == TERM_ANSI && bAnsiParsing) - { pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen); - } - if (pszCurrent == pszNewCurrent) // Pointer didn't move inside Parse function - { - pszNewCurrent += ConWriteString( (char *)pszCurrent, 1); + /* Pointer didn't move inside Parse function */ + if (pszCurrent == pszNewCurrent) { + 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)) + /* Handle special characters including locating the ESC which starts a terminal control seq */ + 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); - } + case 0: /* FALLTHROUGH */ + case 1: /* FALLTHROUGH */ + case 2: /* FALLTHROUGH */ + case 3: /* FALLTHROUGH */ + case 4: /* FALLTHROUGH */ + case 5: /* FALLTHROUGH */ + case 6: /* FALLTHROUGH */ + case 11: /* FALLTHROUGH */ + 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; + } + 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); } - 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); - } - } - if (pszNewCurrent > pszCurrent) - pszBuffer = pszNewCurrent; + + 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++; } - 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; + 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) +unsigned char * +GetNextChar(unsigned char *pszBuffer, unsigned char *pszBufferEnd) { if (++pszBuffer > pszBufferEnd) return NULL; @@ -354,71 +324,71 @@ unsigned char * GetNextChar(unsigned char *pszBuffer, unsigned char *pszBufferEn return pszBuffer; } -void ConSetExtendedMode(int iFunction, BOOL bEnable) +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; + 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; } } @@ -434,440 +404,354 @@ void ConSetExtendedMode(int iFunction, BOOL bEnable) #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) +unsigned char * +ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char **respbuf, size_t *resplen) { - const int nParam = 10; // Maximum number of parameters - + const int nParam = 10; /* Maximum number of parameters */ static int SavedX = 0; static int SavedY = 0; + unsigned char * pszCurrent = pszBuffer; - unsigned char * pszCurrent = pszBuffer; - - if (pszCurrent == NULL || pszBufferEnd == NULL) - return NULL; + 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; + fcompletion = 0; + do { + switch ((unsigned char)*pszCurrent) { + case ';': /* Delimiter */ + 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; + /* Termination Options */ + case 0: + fcompletion = 1; + break; - case '}': - fcompletion = 1; - break; + case '}': + fcompletion = 1; + break; - case '<': // Character set - fcompletion = 1; - break; + case '<': /* Character set */ + fcompletion = 1; + break; - case '\\': - fcompletion = 1; - break; + case '\\': + 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 '^': /* Private message */ + /* while not stop */ + while (pszCurrent && pszCurrent < pszBufferEnd && + _strnicmp((const char *)pszCurrent, (const char *)VT_ST, strlen((const char *)VT_ST))) { + 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 '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 'A': /* Character Set change or Cursor Up */ + if (bMode & MODE_BRK) { /* Cursor UP */ + 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); + case 'B': /* Character set change or Cursor down */ + if (bMode & MODE_BRK) { /* Cursor DOWN */ + if (iParam[0] == 0) + iParam[0] = 1; + ConMoveCursorPosition(0, iParam[0]); + } + fcompletion = 1; + break; - } - fcompletion = 1; - break; + case 'C': /* Character Set change or Cursor right */ + 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 'D': + 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 '=': /* Application mode */ + VTMode |= MODE_APPMODE; + fcompletion = 1; + break; - case '>': // Numeric mode - VTMode &= ~MODE_APPMODE; - fcompletion = 1; - break; + case '>': /* Numeric mode */ + VTMode &= ~MODE_APPMODE; + fcompletion = 1; + break; - case '%': // Character set definitions - 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); - } + case 'h': + if (bMode & MODE_EXT) { + if (iParam[0] == 4 && iParam[1] == 7) { + ConSaveScreen(); } - 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]) - { + } + 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 0) ? iParam[1] - 1 : 0, (iParam[0] > 0) ? iParam[0] - 1 : 0); - } - else if (bMode == 0) - { - //Set tab - } - fcompletion = 1; - bAtEOLN = FALSE; - break; + } 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 'M': - if (iParam[0]) - { - int i ; - for (i=0; i 0) ? iParam[1] - 1 : 0, (iParam[0] > 0) ? iParam[0] - 1 : 0); + + fcompletion = 1; + bAtEOLN = FALSE; + break; - case 'i': // ANSI or VTXXX Print - if ( iParam[0] == 5 ) - { - } - else if ( iParam[0] == 4 ) - InPrintMode = FALSE; - fcompletion = 1; - break; + case 'M': + if (iParam[0]) { + int i; + for (i = 0; i < iParam[0]; i++) + ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY()); + } else { + if (ConGetCursorY() <= ScrollTop + ConWindowSizeY() - 2) + ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY()); + } + fcompletion = 1; + bAtEOLN = FALSE; + break; - case 'K': - if (bMode & MODE_BRK) - { - switch (iParam[0]) - { - case 0: - ConClearEOLine(); - break; - case 1: - ConClearBOLine(); - break; - case 2: - ConClearLine(); - break; - } - } - else if (bMode == 0) - { - bMode |= MODE_K; - } + case 'E': + case 'G': + case 'g': + fcompletion = 1; + break; - fcompletion = 1; - break; + case 'i': /* ANSI or VTXXX Print */ + if (iParam[0] == 4) + InPrintMode = FALSE; + fcompletion = 1; + break; - case 'J': - switch (iParam[0]) + case 'K': + if (bMode & MODE_BRK) { + switch (iParam[0]) { - case 0: - ConClearEOScreen(); + case 0: + ConClearEOLine(); break; - case 1: - ConClearBOScreen(); + case 1: + ConClearBOLine(); break; - case 2: - ConClearScreen(); + case 2: + ConClearLine(); break; } - fcompletion = 1; + } else if (bMode == 0) + bMode |= MODE_K; + + fcompletion = 1; + break; + + case 'J': + switch (iParam[0]) { + case 0: + ConClearEOScreen(); + break; + case 1: + ConClearBOScreen(); break; + case 2: + ConClearScreen(); + break; + } + fcompletion = 1; + break; - case 'n': - if (iCurrentParam == 1) - { - if (iParam[0] == 5) - { - char * szStatus = GetStatusReport(); - if (respbuf != NULL) - { - *respbuf = szStatus; - if (resplen != NULL) - { - *resplen = strlen(szStatus); - } - } + case 'n': + if (iCurrentParam == 1) { + if (iParam[0] == 5) { + char * szStatus = GetStatusReport(); + if (respbuf != NULL) { + *respbuf = szStatus; + if (resplen != NULL) + *resplen = strlen(szStatus); } - else if ( iParam[0] == 6 ) - { - char * szStatus = GetCursorPositionReport(); - if (respbuf != NULL) - { - *respbuf = szStatus; - if (resplen != NULL) - { - *resplen = strlen(szStatus); - } - } + } else if (iParam[0] == 6) { + char * szStatus = GetCursorPositionReport(); + if (respbuf != NULL) { + *respbuf = szStatus; + if (resplen != NULL) + *resplen = strlen(szStatus); } } - fcompletion = 1; - break; + } + fcompletion = 1; + break; - case 'c': - if (bMode == (MODE_BRK & MODE_EXT)) - { - // What is your response? - } - else if (bMode == MODE_BRK) - { - char* szTerminalId = GetTerminalId(); - if (szTerminalId) { - if (respbuf != NULL) - { - *respbuf = szTerminalId; - if (resplen != NULL) - { - *resplen = strlen(szTerminalId); - } - } - } + case 'c': + if (bMode == MODE_BRK) { + char* szTerminalId = GetTerminalId(); + if (szTerminalId) { + if (respbuf != NULL) { + *respbuf = szTerminalId; + if (resplen != NULL) + *resplen = strlen(szTerminalId); + } } - fcompletion = 1; - break; + } + fcompletion = 1; + break; - case 'y': - case 'q': - fcompletion = 1; - break; + case 'y': + case 'q': + fcompletion = 1; + break; - case 'Z': // Identify - This is really a VT52 command - { - char* szTerminalId = GetTerminalId(); - if (szTerminalId) { - *respbuf = szTerminalId; - if (resplen != NULL) - { - *resplen = strlen(szTerminalId); - } - } - } - fcompletion = 1; - break; + case 'Z': /* Identify - This is really a VT52 command */ + { + char* szTerminalId = GetTerminalId(); + if (szTerminalId) { + *respbuf = szTerminalId; + if (resplen != NULL) + *resplen = strlen(szTerminalId); + } + } + fcompletion = 1; + break; - case 'P': - ConDeleteChars(iParam[0]); - fcompletion = 1; - break; + case 'P': + ConDeleteChars(iParam[0]); + fcompletion = 1; + break; default: - - // pszHead should point to digit now. Otherwise we got a bad escape - // sequence, so we just get out of here! - if(*pszCurrent) { - if (!isdigit(*pszCurrent)) - { + /* pszHead should point to digit now. Otherwise we got a bad escape + * sequence, so we just get out of here! + */ + if (*pszCurrent) { + if (!isdigit(*pszCurrent)) { pszCurrent = pszBuffer; return pszCurrent; } iParam[iCurrentParam] = strtoul((const char *)pszCurrent, (char **)&pszCurrent, 10); - pszCurrent--; - if (iCurrentParam < nParam) iCurrentParam++; - // Check for digit completion + /* Check for digit completion */ if (bMode & DIGI_MASK) fcompletion = 1; - - if (bMode == 0) - { - switch(iParam[0]) - { - case 7: - SavedX = ConGetCursorX(); - SavedY = ConGetCursorY(); - break; - case 8: - ConSetCursorPosition(SavedX, SavedY); - break; + + if (bMode == 0) { + switch (iParam[0]) { + case 7: + SavedX = ConGetCursorX(); + SavedY = ConGetCursorY(); + break; + case 8: + ConSetCursorPosition(SavedX, SavedY); + break; } fcompletion = 1; } - } - else { - pszCurrent = pszBuffer; - return pszCurrent; - } - + } else { + pszCurrent = pszBuffer; + return pszCurrent; + } break; } - } while ((++pszCurrent < pszBufferEnd) && !fcompletion); + } while ((++pszCurrent < pszBufferEnd) && !fcompletion); - if (fcompletion) - { + if (fcompletion) { memset(iParam, '\0', sizeof(iParam)); iCurrentParam = 0; bDelimiter = 0; @@ -878,7 +762,6 @@ unsigned char * ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEn bBkMode = 0; bCharMode = 0; return pszCurrent; - } - else + } else return pszBuffer; } diff --git a/contrib/win32/win32compat/console.c b/contrib/win32/win32compat/console.c index c1b18ff2..eb6b717d 100644 --- a/contrib/win32/win32compat/console.c +++ b/contrib/win32/win32compat/console.c @@ -4,7 +4,9 @@ * Copyright (c) 2015 Microsoft Corp. * All rights reserved * - * Microsoft openssh win32 port + * 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 @@ -27,21 +29,15 @@ * (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 +#include "console.h" + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4 #endif @@ -56,1552 +52,1421 @@ int ScrollTop; int ScrollBottom; int LastCursorX; int LastCursorY; - BOOL bAnsiParsing = FALSE; - char *pSavedScreen = NULL; -static COORD ZeroCoord = {0,0}; -COORD SavedScreenSize = {0,0}; -COORD SavedScreenCursor = {0, 0 }; -SMALL_RECT SavedViewRect = {0,0,0,0}; +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; +typedef struct _SCREEN_RECORD { + PCHAR_INFO pScreenBuf; + COORD ScreenSize; + COORD ScreenCursor; + SMALL_RECT srWindowRect; +}SCREEN_RECORD, *PSCREEN_RECORD; PSCREEN_RECORD pSavedScreenRec = NULL; int in_raw_mode = 0; -/* ************************************************************ */ -/* Function: ConInit */ -/* Used to Initialize the Console for output */ -/* ************************************************************ */ -int ConInit( DWORD OutputHandle, BOOL fSmartInit ) +/* Used to Initialize the Console for output */ +int +ConInit(DWORD OutputHandle, BOOL fSmartInit) { - OSVERSIONINFO os; - DWORD dwAttributes = 0; - DWORD dwRet = 0; - BOOL bRet = FALSE; - 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 on OutputHandle failed with %d\n", dwRet); - return dwRet; - } - - if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) { - dwRet = GetLastError(); - printf("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); - return dwRet; - } - - dwAttributes = dwSavedAttributes; - dwAttributes &= ~(ENABLE_LINE_INPUT | - ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); - dwAttributes |= ENABLE_WINDOW_INPUT; - - if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes)) { // Windows NT - dwRet = GetLastError(); - printf("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); - return dwRet; - } - - if (!GetConsoleMode(hOutputConsole, &dwAttributes)) { - dwRet = GetLastError(); - printf("GetConsoleMode on hOutputConsole failed with %d\n", dwRet); - return dwRet; - } - - dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING; - - if (!SetConsoleMode(hOutputConsole, dwAttributes)) { // Windows NT - bAnsiParsing = TRUE; - } - - ConSetScreenX(); - ConSetScreenY(); - ScrollTop = 0; - ScrollBottom = ConWindowSizeY(); - - if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) - SavedViewRect = csbi.srWindow; + OSVERSIONINFO os; + DWORD dwAttributes = 0; + DWORD dwRet = 0; + BOOL bRet = FALSE; + 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 on OutputHandle failed with %d\n", dwRet); + return dwRet; + } + + if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) { + dwRet = GetLastError(); + printf("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); + return dwRet; + } + + dwAttributes = dwSavedAttributes; + dwAttributes &= ~(ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); + dwAttributes |= ENABLE_WINDOW_INPUT; + + if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes)) { /* Windows NT */ + dwRet = GetLastError(); + printf("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); + return dwRet; + } + + if (!GetConsoleMode(hOutputConsole, &dwAttributes)) { + dwRet = GetLastError(); + printf("GetConsoleMode on hOutputConsole failed with %d\n", dwRet); + return dwRet; + } + + dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + if (!SetConsoleMode(hOutputConsole, dwAttributes)) /* Windows NT */ + bAnsiParsing = TRUE; + + ConSetScreenX(); + ConSetScreenY(); + ScrollTop = 0; + ScrollBottom = ConWindowSizeY(); + + if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) + SavedViewRect = csbi.srWindow; in_raw_mode = 1; - return 0; + return 0; } - -/* ************************************************************ */ -/* Function: ConUnInit */ -/* Used to Uninitialize the Console */ -/* ************************************************************ */ -int ConUnInit( void ) +/* Used to Uninitialize the Console */ +int +ConUnInit(void) { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; in_raw_mode = 0; - if ( hOutputConsole == NULL ) - return 0; + if (hOutputConsole == NULL) + return 0; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return 0; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return 0; - SetConsoleMode(hOutputConsole, dwSavedAttributes); + SetConsoleMode(hOutputConsole, dwSavedAttributes); - return 0; + return 0; } -/* ************************************************************ */ -/* Function: ConUnInit */ -/* Used to Uninitialize the Console */ -/* ************************************************************ */ -int ConUnInitWithRestore( void ) +/* 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; + 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 +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 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 +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; + 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) +/* 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; + 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 '\r': + ConSetCursorPosition(0, Y); + + break; + case '\n': + Y++; + if (Y > ScrollBottom - 1) { + ConScrollDown(ScrollTop, ScrollBottom); + ConSetCursorPosition(0, ScrollBottom); + } else + ConSetCursorPosition(0, Y); + break; + default: + fOkay = (BOOL)WriteConsole(hOutputConsole, &ch, 1, (LPDWORD)&Result, 0); + + /* last coord */ + if (X >= ScreenX - 1) { + if (Y >= ScrollBottom - 1) { /* last coord */ + ConScrollDown(ScrollTop, ScrollBottom); + ConMoveCursorPosition(-ConGetCursorX(), 0); + } else + ConMoveCursorPosition(-ConGetCursorX(), 1); + } + break; + } + + return fOkay; } - -BOOL ConWriteCharW(WCHAR ch) +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; + 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 +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; + int X, CurrentY, CurrentX, Result; + + for (X = 0; (X < NumChars) && (pData[X] != '\0'); X++) { + switch (pData[X]) { + case 0: /* FALLTHROUGH */ + case 1: /* FALLTHROUGH */ + case 2: /* FALLTHROUGH */ + case 3: /* FALLTHROUGH */ + case 4: /* FALLTHROUGH */ + case 5: /* FALLTHROUGH */ + case 6: /* FALLTHROUGH */ + case 11: /* FALLTHROUGH */ + 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: /* FALLTHROUGH */ + 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 +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 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); + + 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 +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; + 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, ... ) +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 ); + va_list va_data; + int len; + char temp[4096]; - len = vsnprintf( Temp, sizeof(Temp), Format, va_data ); + 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); - ConWriteConsole(Temp, len); - - va_end( va_data ); - - return len; + return len; } -BOOL ConDisplayCursor( BOOL bVisible ) +BOOL +ConDisplayCursor(BOOL bVisible) { - CONSOLE_CURSOR_INFO ConsoleCursorInfo; - - if (GetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo)) { + CONSOLE_CURSOR_INFO ConsoleCursorInfo; - ConsoleCursorInfo.bVisible = bVisible; + if (GetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo)) { + ConsoleCursorInfo.bVisible = bVisible; + return SetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo); + } - return SetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo); - } - - return FALSE; + return FALSE; } -void ConClearScreen(void) +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 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); +} - DWORD dwNumChar = (ConsoleInfo.srWindow.Bottom + 1) * - (ConsoleInfo.srWindow.Right + 1); +void +ConClearScrollRegion() +{ + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; - FillConsoleOutputCharacter(hOutputConsole, ' ', - dwNumChar, - Coord, &dwWritten); - FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, - dwNumChar, - Coord, &dwWritten); + Coord.X = 0; + Coord.Y = ScrollTop + consoleInfo.srWindow.Top; + FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)consoleInfo.dwSize.X * (DWORD)ScrollBottom, + Coord, &dwWritten); - srcWindow = ConsoleInfo.srWindow; + FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, + (DWORD)consoleInfo.dwSize.X * (DWORD)ScrollBottom, Coord, &dwWritten); - ConSetCursorPosition(0, 0); + ConSetCursorPosition(0, ScrollTop); } -void ConClearScrollRegion() +void +ConClearEOScreen() { - 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 ); + 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 ConClearEOScreen() +void +ConClearBOScreen() { - 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(); + 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 ConClearBOScreen() +void +ConClearLine() { - 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(); + 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 ConClearLine() +void +ConClearEOLine() { - 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); + 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 ConClearEOLine() +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)(ScreenX - ConGetCursorX()), - Coord, &dwWritten); - FillConsoleOutputAttribute(hOutputConsole, ConsoleInfo.wAttributes, - (DWORD)(ScreenX - ConGetCursorX()), - Coord, &dwWritten); + 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 ConClearNFromCursorRight(int n) +void +ConClearNFromCursorLeft(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); -} + DWORD dwWritten; + COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; -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); + 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() +void +ConScrollDownEntireBuffer() { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return; - ConScrollDown(0, ConsoleInfo.dwSize.Y - 1); - return; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; + ConScrollDown(0, consoleInfo.dwSize.Y - 1); + return; } -void ConScrollUpEntireBuffer() +void +ConScrollUpEntireBuffer() { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return; - ConScrollUp(0, ConsoleInfo.dwSize.Y - 1); - return; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; + ConScrollUp(0, consoleInfo.dwSize.Y - 1); + return; } -void ConScrollUp(int topline,int botline) +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 - ); + 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) +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 - ); + 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() +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); + 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) +void +ConSetCursorPosition(int x, int y) { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - COORD Coord; - int rc; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + COORD Coord; + int rc; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; - Coord.X = (short)(x); - Coord.Y = (short)(y); + 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 - 1) && y > LastCursorY) { + for (int n = LastCursorY; n < y; n++) + GoToNextLine(); + } - if (y >= ConsoleInfo.dwSize.Y) { - Coord.Y = ConsoleInfo.dwSize.Y - 1; - } + if (y >= consoleInfo.dwSize.Y) { + Coord.Y = consoleInfo.dwSize.Y - 1; + } - if (!SetConsoleCursorPosition(hOutputConsole, Coord)) - rc = GetLastError(); + if (!SetConsoleCursorPosition(hOutputConsole, Coord)) + rc = GetLastError(); - LastCursorX = x; - LastCursorY = y; + LastCursorX = x; + LastCursorY = y; } -BOOL ConChangeCursor( CONSOLE_CURSOR_INFO *pCursorInfo ) +BOOL +ConChangeCursor(CONSOLE_CURSOR_INFO *pCursorInfo) { - return SetConsoleCursorInfo( hOutputConsole, pCursorInfo ); + return SetConsoleCursorInfo(hOutputConsole, pCursorInfo); } -int ConGetCursorX() +int +ConGetCursorX() { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return 0; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return 0; - return ConsoleInfo.dwCursorPosition.X; + return consoleInfo.dwCursorPosition.X; } -int ConGetCursorY() +int +ConGetCursorY() { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - { - return 0; - } + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return 0; - return (ConsoleInfo.dwCursorPosition.Y - ConsoleInfo.srWindow.Top); + return (consoleInfo.dwCursorPosition.Y - consoleInfo.srWindow.Top); } -int ConGetCursorInBufferY() +int +ConGetCursorInBufferY() { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - { - return 0; - } + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return 0; - return (ConsoleInfo.dwCursorPosition.Y); + return (consoleInfo.dwCursorPosition.Y); } -void ConMoveCursorPosition(int x, int y) +void +ConMoveCursorPosition(int x, int y) { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; - COORD Coord; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + COORD Coord; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; - Coord.X = (short)(ConsoleInfo.dwCursorPosition.X + x); - Coord.Y = (short)(ConsoleInfo.dwCursorPosition.Y + y); + Coord.X = (short)(consoleInfo.dwCursorPosition.X + x); + Coord.Y = (short)(consoleInfo.dwCursorPosition.Y + y); - SetConsoleCursorPosition(hOutputConsole, Coord); + SetConsoleCursorPosition(hOutputConsole, Coord); } -void ConGetRelativeCursorPosition(int *x, int *y) +void +ConGetRelativeCursorPosition(int *x, int *y) { - CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return; - *x -= ConsoleInfo.srWindow.Left; - *y -= ConsoleInfo.srWindow.Top; + *x -= consoleInfo.srWindow.Left; + *y -= consoleInfo.srWindow.Top; } -void ConDeleteChars(int n) +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); + 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, /* console screen buffer handle */ + (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 ) +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); + 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, /* console screen buffer handle */ + (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 +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 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( ) +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; + 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 (hOutputConsole == NULL) + return FALSE; - if ( pSavedScreen == NULL ) - return FALSE; + if (pSavedScreen == NULL) + return FALSE; - if (!GetConsoleScreenBufferInfo(hOutputConsole, &ConsoleInfo)) - return (FALSE); + if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) + return (FALSE); - beginOfScreen.X = ConsoleInfo.srWindow.Left; - beginOfScreen.Y = ConsoleInfo.srWindow.Top; + beginOfScreen.X = consoleInfo.srWindow.Left; + beginOfScreen.Y = consoleInfo.srWindow.Top; - FillConsoleOutputCharacter(hOutputConsole, ' ', - (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, - beginOfScreen, &dwWritten); + FillConsoleOutputCharacter(hOutputConsole, ' ', + (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, + beginOfScreen, &dwWritten); - pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); - SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); + pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); + SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); - FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, - (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, - beginOfScreen, &dwWritten); + FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, + (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, + beginOfScreen, &dwWritten); - return fOkay; + return fOkay; } -void ConDeleteScreenHandle( SCREEN_HANDLE hScreen ) +void +ConDeleteScreenHandle(SCREEN_HANDLE hScreen) { - PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)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); + free(pScreenRec->pScreenBuf); + free(pScreenRec); } -void ConRestoreViewRect( void ) +/* Restores Previous Saved screen info and buffer */ +BOOL +ConRestoreScreen(void) { - //SetConsoleWindowInfo(hOutputConsole,TRUE,&SavedViewRect); + return ConRestoreScreenHandle(pSavedScreenRec); } -/* ************************************************************ */ -/* Function: ConSaveScreen */ -/* Saves current screen info and buffer */ -/* ************************************************************ */ -BOOL ConSaveScreen( void ) +/* Saves current screen info and buffer */ +BOOL +ConSaveScreen(void) { - pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec); - return TRUE; + pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec); + return TRUE; } -void ConSaveViewRect( void ) +void +ConSaveViewRect(void) { - CONSOLE_SCREEN_BUFFER_INFO csbi; - - if (!GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) - return; + CONSOLE_SCREEN_BUFFER_INFO csbi; - SavedViewRect = csbi.srWindow; + if (!GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) + return; + SavedViewRect = csbi.srWindow; } -BOOL ConIsRedirected(HANDLE hInput) +BOOL +ConIsRedirected(HANDLE hInput) { - DWORD dwMode; - - return !GetConsoleMode(hInput, &dwMode); + DWORD dwMode; + return !GetConsoleMode(hInput, &dwMode); } -HANDLE GetConsoleOutputHandle() +HANDLE +GetConsoleOutputHandle() { - SECURITY_ATTRIBUTES sa; + SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; - HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE); + 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); - } + if (ConIsRedirected(hTemp)) + hTemp = CreateFile(TEXT("CONOUT$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); - return hTemp; + return hTemp; } -HANDLE GetConsoleInputHandle() +HANDLE +GetConsoleInputHandle() { - SECURITY_ATTRIBUTES sa; + SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; - HANDLE hTemp = GetStdHandle(STD_INPUT_HANDLE); + 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); - } + if (ConIsRedirected(hTemp)) + hTemp = CreateFile(TEXT("CONIN$"), GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + &sa, OPEN_EXISTING, 0, NULL); - return hTemp; + return hTemp; } -void ConSaveWindowsState(void) +void +ConSaveWindowsState(void) { - CONSOLE_SCREEN_BUFFER_INFOEX csbiex; - csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + CONSOLE_SCREEN_BUFFER_INFOEX csbiex; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - if (!GetConsoleScreenBufferInfoEx(hOutputConsole, &csbiex)) - return; + if (!GetConsoleScreenBufferInfoEx(hOutputConsole, &csbiex)) + return; - SavedWindowState = csbiex; + SavedWindowState = csbiex; } diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index f8ab73c4..06745d16 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -32,9 +32,10 @@ #include #include #include -#include "w32fd.h" #include #include + +#include "w32fd.h" #include "inc\utf.h" #include "misc_internal.h" @@ -44,6 +45,14 @@ #define WRITE_BUFFER_SIZE 100*1024 #define errno_from_Win32LastError() errno_from_Win32Error(GetLastError()) +struct createFile_flags { + DWORD dwDesiredAccess; + DWORD dwShareMode; + SECURITY_ATTRIBUTES securityAttributes; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; +}; + int termio_initiate_read(struct w32_io* pio); int termio_initiate_write(struct w32_io* pio, DWORD num_bytes); @@ -73,7 +82,8 @@ static int pipe_counter = 0; * to it. These handles are associated with read end and write end of the pipe */ int -fileio_pipe(struct w32_io* pio[2]) { +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[PATH_MAX]; @@ -158,18 +168,10 @@ fileio_pipe(struct w32_io* pio[2]) { 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) { - +createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) +{ /* check flags */ int rwflags = flags & 0x3; int c_s_flags = flags & 0xfffffff0; @@ -185,8 +187,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { } /*only following create and status flags currently supported*/ - if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC - | O_EXCL | O_BINARY)) { + 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; @@ -204,7 +205,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { switch (rwflags) { case O_RDONLY: cf_flags->dwDesiredAccess = GENERIC_READ; - cf_flags->dwShareMode = FILE_SHARE_READ; + cf_flags->dwShareMode = FILE_SHARE_READ; break; case O_WRONLY: cf_flags->dwDesiredAccess = GENERIC_WRITE; @@ -226,7 +227,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { cf_flags->dwCreationDisposition = CREATE_NEW; else cf_flags->dwCreationDisposition = CREATE_ALWAYS; - } + } if (c_s_flags & O_APPEND) cf_flags->dwDesiredAccess = FILE_APPEND_DATA; @@ -240,11 +241,12 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) { /* open() implementation. Uses CreateFile to open file, console, device, etc */ struct w32_io* - fileio_open(const char *path_utf8, int flags, int mode) { +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; + wchar_t *path_utf16 = NULL; debug2("open - pathname:%s, flags:%d, mode:%d", path_utf8, flags, mode); /* check input params*/ @@ -254,12 +256,12 @@ struct w32_io* return NULL; } - if ((path_utf16 = utf8_to_utf16(path_utf8)) == NULL) { - errno = ENOMEM; - debug("utf8_to_utf16 failed - ERROR:%d", GetLastError()); - return NULL; - } - + if ((path_utf16 = utf8_to_utf16(path_utf8)) == NULL) { + errno = ENOMEM; + debug("utf8_to_utf16 failed for file:%s error:%d", path_utf8, GetLastError()); + return NULL; + } + if (createFile_flags_setup(flags, mode, &cf_flags) == -1) return NULL; @@ -269,17 +271,17 @@ struct w32_io* if (handle == INVALID_HANDLE_VALUE) { errno = errno_from_Win32LastError(); - debug("open - CreateFile ERROR:%d", GetLastError()); - free(path_utf16); + debug("failed to open file:%s error:%d", path_utf8, GetLastError()); + free(path_utf16); return NULL; } - free(path_utf16); + free(path_utf16); pio = (struct w32_io*)malloc(sizeof(struct w32_io)); if (pio == NULL) { CloseHandle(handle); errno = ENOMEM; - debug("open - ERROR:%d", errno); + debug("fileio_open(), failed to allocate memory error:%d", errno); return NULL; } @@ -292,13 +294,10 @@ struct w32_io* 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)); +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; @@ -311,7 +310,8 @@ VOID CALLBACK ReadCompletionRoutine( /* 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) { +fileio_ReadFileEx(struct w32_io* pio, unsigned int bytes_requested) +{ debug2("ReadFileEx io:%p", pio); if (pio->read_details.buf == NULL) { @@ -342,11 +342,11 @@ fileio_ReadFileEx(struct w32_io* pio, unsigned int bytes_requested) { /* read() implementation */ int -fileio_read(struct w32_io* pio, void *dst, unsigned int max) { +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)) { @@ -426,11 +426,11 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { return bytes_copied; } -VOID CALLBACK WriteCompletionRoutine( - _In_ DWORD dwErrorCode, - _In_ DWORD dwNumberOfBytesTransfered, - _Inout_ LPOVERLAPPED lpOverlapped - ) { +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", @@ -450,21 +450,18 @@ VOID CALLBACK WriteCompletionRoutine( /* write() implementation */ int -fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { +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)) - { + if (w32_io_is_blocking(pio)) { debug2("write - io pending, blocking call made, io:%p", pio); - while (pio->write_details.pending) { + while (pio->write_details.pending) if (wait_for_any_event(NULL, 0, INFINITE) == -1) return -1; - } - } - else { + } else { errno = EAGAIN; debug2("write - IO is already pending, io:%p", pio); return -1; @@ -502,14 +499,12 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { } else return -1; - } - else { + } 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 { + } else { errno = errno_from_Win32LastError(); /* read end of the pipe closed ? */ if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_BROKEN_PIPE)) { @@ -531,6 +526,7 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { } } } + /* execute APC to give a chance for write to complete */ SleepEx(0, TRUE); @@ -548,8 +544,8 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { /* fstat() implemetation */ int -fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { - +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) { @@ -561,12 +557,23 @@ fileio_fstat(struct w32_io* pio, struct _stat64 *buf) { } int -fileio_stat(const char *path, struct _stat64 *buf) { +fileio_stat(const char *path, struct _stat64 *buf) +{ wchar_t wpath[PATH_MAX]; wchar_t* wtmp = NULL; + struct w32_io* pio; if ((wtmp = utf8_to_utf16(path)) == NULL) fatal("failed to covert input arguments"); + + /* If we doesn't have sufficient permissions then _wstat4() is returning + * file not found so added fileio_open() which will set the errorno correctly (access denied) + */ + if (NULL == (pio = fileio_open(path, O_RDONLY, 0))) + return -1; + + fileio_close(pio); + wcscpy(&wpath[0], wtmp); free(wtmp); @@ -574,7 +581,8 @@ fileio_stat(const char *path, struct _stat64 *buf) { } long -fileio_lseek(struct w32_io* pio, long offset, int origin) { +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); @@ -589,13 +597,12 @@ fileio_lseek(struct w32_io* pio, long offset, int origin) { /* fdopen implementation */ FILE* -fileio_fdopen(struct w32_io* pio, const char *mode) { - +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 */ - if (mode[1] == '\0') { switch (*mode) { case 'r': @@ -611,8 +618,7 @@ fileio_fdopen(struct w32_io* pio, const char *mode) { debug("fdopen - ERROR unsupported mode %s", mode); return NULL; } - } - else { + } else { errno = ENOTSUP; debug("fdopen - ERROR unsupported mode %s", mode); return NULL; @@ -630,8 +636,8 @@ fileio_fdopen(struct w32_io* pio, const char *mode) { } void -fileio_on_select(struct w32_io* pio, BOOL rd) { - +fileio_on_select(struct w32_io* pio, BOOL rd) +{ if (!rd) return; @@ -643,8 +649,7 @@ fileio_on_select(struct w32_io* pio, BOOL rd) { errno = 0; return; } - } - else { + } else { if (fileio_ReadFileEx(pio, INT_MAX) != 0) { pio->read_details.error = errno; errno = 0; @@ -653,16 +658,15 @@ fileio_on_select(struct w32_io* pio, BOOL rd) { } } - int -fileio_close(struct w32_io* pio) { - +fileio_close(struct w32_io* pio) +{ debug2("fileclose - pio:%p", pio); CancelIo(WINHANDLE(pio)); - //let queued APCs (if any) drain + /* let queued APCs (if any) drain */ SleepEx(0, TRUE); - if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed + if (pio->type != STD_IO_FD) { /* STD handles are never explicitly closed */ CloseHandle(WINHANDLE(pio)); if (pio->read_details.buf) @@ -677,14 +681,14 @@ fileio_close(struct w32_io* pio) { } BOOL -fileio_is_io_available(struct w32_io* pio, BOOL rd) { +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 + } else { /* write */ return (pio->write_details.pending == FALSE) ? TRUE : FALSE; } } \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/pwd.h b/contrib/win32/win32compat/inc/pwd.h index 49e6aab5..a60f83a9 100644 --- a/contrib/win32/win32compat/inc/pwd.h +++ b/contrib/win32/win32compat/inc/pwd.h @@ -13,13 +13,14 @@ #include "sys\types.h" struct passwd { - char *pw_name; /* user's login name */ - char *pw_passwd; /* password? */ + 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 */ + char *pw_sid; /* sid of user */ }; /*start - declarations not applicable in Windows */ diff --git a/contrib/win32/win32compat/inc/signal.h b/contrib/win32/win32compat/inc/signal.h index 3b98fa38..5eeba779 100644 --- a/contrib/win32/win32compat/inc/signal.h +++ b/contrib/win32/win32compat/inc/signal.h @@ -52,8 +52,10 @@ typedef int sigset_t; #define W32_SIG_IGN ((sighandler_t)1) sighandler_t w32_signal(int signum, sighandler_t handler); -#define signal(a,b) w32_signal((a), (b)) -#define mysignal(a,b) w32_signal((a), (b)) +//#define signal(a,b) w32_signal((a), (b)) +//#define mysignal(a,b) w32_signal((a), (b)) +sighandler_t mysignal(int signum, sighandler_t handler); + int w32_raise(int sig); #define raise(a) w32_raise(a) diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index efabfef3..9e87efa1 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -30,105 +30,202 @@ #include #include +#include +#include + #include "inc\sys\stat.h" #include "inc\sys\statvfs.h" #include "inc\sys\time.h" -#include -#include #include "misc_internal.h" #include "inc\dlfcn.h" #include "inc\dirent.h" #include "inc\sys\types.h" #include "inc\sys\ioctl.h" #include "inc\fcntl.h" +#include "inc\utf.h" #include "signal_internal.h" -int usleep(unsigned int useconds) +static char* s_programdir = NULL; + +/* 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; + +/* Windows CRT defines error string messages only till 43 in errno.h + * This is an extended list that defines messages for EADDRINUSE through EWOULDBLOCK + */ +char* _sys_errlist_ext[] = { + "Address already in use", /* EADDRINUSE 100 */ + "Address not available", /* EADDRNOTAVAIL 101 */ + "Address family not supported", /* EAFNOSUPPORT 102 */ + "Connection already in progress", /* EALREADY 103 */ + "Bad message", /* EBADMSG 104 */ + "Operation canceled", /* ECANCELED 105 */ + "Connection aborted", /* ECONNABORTED 106 */ + "Connection refused", /* ECONNREFUSED 107 */ + "Connection reset", /* ECONNRESET 108 */ + "Destination address required", /* EDESTADDRREQ 109 */ + "Host is unreachable", /* EHOSTUNREACH 110 */ + "Identifier removed", /* EIDRM 111 */ + "Operation in progress", /* EINPROGRESS 112 */ + "Socket is connected", /* EISCONN 113 */ + "Too many levels of symbolic links", /* ELOOP 114 */ + "Message too long", /* EMSGSIZE 115 */ + "Network is down", /* ENETDOWN 116 */ + "Connection aborted by network", /* ENETRESET 117 */ + "Network unreachable", /* ENETUNREACH 118 */ + "No buffer space available", /* ENOBUFS 119 */ + "No message is available on the STREAM head read queue",/* ENODATA 120 */ + "Link has been severed", /* ENOLINK 121 */ + "No message of the desired type", /* ENOMSG 122 */ + "Protocol not available", /* ENOPROTOOPT 123 */ + "No STREAM resources", /* ENOSR 124 */ + "Not a STREAM", /* ENOSTR 125 */ + "The socket is not connected", /* ENOTCONN 126 */ + "enotecoverable", /* ENOTRECOVERABLE 127 */ + "Not a socket", /* ENOTSOCK 128 */ + "Operation not supported", /* ENOTSUP 129 */ + "Operation not supported on socket", /* EOPNOTSUPP 130 */ + "eother", /* EOTHER 131 */ + "Value too large to be stored in data type", /* EOVERFLOW 132 */ + "eownerdead", /* EOWNERDEAD 133 */ + "Protocol error", /* EPROTO 134 */ + "Protocol not supported", /* EPROTONOSUPPORT 135 */ + "Protocol wrong type for socket", /* EPROTOTYPE 136 */ + "Timer expired", /* ETIME 137 */ + "Connection timed out", /* ETIMEDOUT 138 */ + "Text file busy", /* ETXTBSY 139 */ + "Operation would block" /* EWOULDBLOCK 140 */ +}; + +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; - } +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 -*/ + * 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; + union { + FILETIME ft; + unsigned long long ns; + } timehelper; + unsigned long long us; - /* Fetch time since Jan 1, 1601 in 100ns increments */ - GetSystemTimeAsFileTime(&timehelper.ft); + /* Fetch time since Jan 1, 1601 in 100ns increments */ + GetSystemTimeAsFileTime(&timehelper.ft); - /* Convert to microseconds from 100 ns units */ - us = timehelper.ns / 10; + /* Convert to microseconds from 100 ns units */ + us = timehelper.ns / 10; - /* Remove the epoch difference */ - us -= EPOCH_DELTA_US; + /* 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); + /* Stuff result into the timeval */ + tv->tv_sec = (long)(us / 1000000ULL); + tv->tv_usec = (long)(us % 1000000ULL); - return 0; + return 0; } void -explicit_bzero(void *b, size_t len) { +explicit_bzero(void *b, size_t len) +{ SecureZeroMemory(b, len); } -HMODULE dlopen(const char *filename, int flags) { +HMODULE +dlopen(const char *filename, int flags) +{ return LoadLibraryA(filename); } -int dlclose(HMODULE handle) { +int +dlclose(HMODULE handle) +{ FreeLibrary(handle); return 0; } -FARPROC dlsym(HMODULE handle, const char *symbol) { +FARPROC +dlsym(HMODULE handle, const char *symbol) +{ return GetProcAddress(handle, symbol); } @@ -136,8 +233,9 @@ FARPROC dlsym(HMODULE handle, const char *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) { +FILE * +w32_fopen_utf8(const char *path, const char *mode) +{ wchar_t wpath[PATH_MAX], wmode[5]; FILE* f; char utf8_bom[] = { 0xEF,0xBB,0xBF }; @@ -149,7 +247,7 @@ w32_fopen_utf8(const char *path, const char *mode) { } if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, PATH_MAX) == 0 || - MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 5) == 0) { + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, 5) == 0) { errno = EFAULT; debug("WideCharToMultiByte failed for %c - ERROR:%d", path, GetLastError()); return NULL; @@ -166,11 +264,10 @@ w32_fopen_utf8(const char *path, const char *mode) { return NULL; }*/ - } - else if (mode[0] == 'r' && fseek(f, 0, SEEK_SET) != EBADF) { + } 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) { + memcmp(first3_bytes, utf8_bom, 3) != 0) { fseek(f, 0, SEEK_SET); } } @@ -179,86 +276,64 @@ w32_fopen_utf8(const char *path, const char *mode) { return f; } +char * +w32_programdir() +{ + if (s_programdir != NULL) + return s_programdir; -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; - 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--; - /* 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 */ - if (tail > s_programdir) - *tail = '\0'; - else - *tail = '.'; /* current directory */ - } + return s_programdir; +} - 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; + } } -int -daemon(int nochdir, int noclose) +int +spawn_child(char* cmd, int in, int out, int err, DWORD flags) { - 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; - } -} - -int -spawn_child(char* cmd, int in, int out, int err, DWORD flags) { PROCESS_INFORMATION pi; STARTUPINFOW si; BOOL b; @@ -267,8 +342,8 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) { int add_module_path = 0; /* should module path be added */ - do{ - if(!cmd) + do { + if (!cmd) break; t = cmd; if (*t == '\"') @@ -276,7 +351,6 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) { if (t[0] == '\0' || t[0] == '\\' || t[0] == '.' || t[1] == ':') break; add_module_path = 1; - } while (0); /* add current module path to start if needed */ @@ -292,10 +366,9 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) { ctr += strlen(w32_programdir()); *ctr++ = '\\'; memcpy(ctr, cmd, strlen(cmd) + 1); - } - else + } else abs_cmd = cmd; - + debug("spawning %s", abs_cmd); if ((cmd_utf16 = utf8_to_utf16(abs_cmd)) == NULL) { @@ -303,7 +376,7 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) { return -1; } - if(abs_cmd != cmd) + if (abs_cmd != cmd) free(abs_cmd); memset(&si, 0, sizeof(STARTUPINFOW)); @@ -322,8 +395,7 @@ spawn_child(char* cmd, int in, int out, int err, DWORD flags) { pi.dwProcessId = -1; } CloseHandle(pi.hThread); - } - else { + } else { errno = GetLastError(); pi.dwProcessId = -1; } @@ -343,15 +415,9 @@ strmode(mode_t mode, char *p) 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'; @@ -364,82 +430,84 @@ strmode(mode_t mode, char *p) *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. + + /* 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 */ + /* //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) { +int +w32_chmod(const char *pathname, mode_t mode) +{ int ret; wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(pathname)); if (resolvedPathName_utf16 == NULL) { @@ -451,16 +519,17 @@ w32_chmod(const char *pathname, mode_t mode) { return ret; } -int -w32_chown(const char *pathname, unsigned int owner, unsigned int group) { +int +w32_chown(const char *pathname, unsigned int owner, unsigned int group) +{ /* TODO - implement this */ errno = EOPNOTSUPP; return -1; } static void -unix_time_to_file_time(ULONG t, LPFILETIME pft) { - +unix_time_to_file_time(ULONG t, LPFILETIME pft) +{ ULONGLONG ull; ull = UInt32x32To64(t, 10000000) + 116444736000000000; @@ -469,7 +538,8 @@ unix_time_to_file_time(ULONG t, LPFILETIME pft) { } static int -settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime) { +settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime) +{ HANDLE handle; handle = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); @@ -493,7 +563,8 @@ settimes(wchar_t * path, FILETIME *cretime, FILETIME *acttime, FILETIME *modtime } int -w32_utimes(const char *filename, struct timeval *tvp) { +w32_utimes(const char *filename, struct timeval *tvp) +{ int ret; FILETIME acttime, modtime; wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(filename)); @@ -511,25 +582,28 @@ w32_utimes(const char *filename, struct timeval *tvp) { return ret; } -int -w32_symlink(const char *target, const char *linkpath) { - // Not supported in windows +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 +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) { +w32_rename(const char *old_name, const char *new_name) +{ wchar_t *resolvedOldPathName_utf16 = utf8_to_utf16(sanitized_path(old_name)); wchar_t *resolvedNewPathName_utf16 = utf8_to_utf16(sanitized_path(new_name)); - + if (NULL == resolvedOldPathName_utf16 || NULL == resolvedNewPathName_utf16) { errno = ENOMEM; return -1; @@ -542,17 +616,16 @@ w32_rename(const char *old_name, const char *new_name) { */ struct _stat64 st; if (fileio_stat(sanitized_path(new_name), &st) != -1) { - if(((st.st_mode & _S_IFMT) == _S_IFREG)) { + if (((st.st_mode & _S_IFMT) == _S_IFREG)) w32_unlink(new_name); - } else { + else { DIR *dirp = opendir(new_name); if (NULL != dirp) { struct dirent *dp = readdir(dirp); closedir(dirp); - if (dp == NULL) { + if (dp == NULL) w32_rmdir(new_name); - } } } } @@ -565,8 +638,8 @@ w32_rename(const char *old_name, const char *new_name) { } int -w32_unlink(const char *path) { - +w32_unlink(const char *path) +{ wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(path)); if (NULL == resolvedPathName_utf16) { errno = ENOMEM; @@ -580,7 +653,8 @@ w32_unlink(const char *path) { } int -w32_rmdir(const char *path) { +w32_rmdir(const char *path) +{ wchar_t *resolvedPathName_utf16 = utf8_to_utf16(sanitized_path(path)); if (NULL == resolvedPathName_utf16) { errno = ENOMEM; @@ -593,8 +667,9 @@ w32_rmdir(const char *path) { return returnStatus; } -int -w32_chdir(const char *dirname_utf8) { +int +w32_chdir(const char *dirname_utf8) +{ wchar_t *dirname_utf16 = utf8_to_utf16(dirname_utf8); if (dirname_utf16 == NULL) { errno = ENOMEM; @@ -608,7 +683,8 @@ w32_chdir(const char *dirname_utf8) { } char * -w32_getcwd(char *buffer, int maxlen) { +w32_getcwd(char *buffer, int maxlen) +{ wchar_t wdirname[PATH_MAX]; char* putf8 = NULL; @@ -623,8 +699,8 @@ w32_getcwd(char *buffer, int maxlen) { } int -w32_mkdir(const char *path_utf8, unsigned short mode) { - +w32_mkdir(const char *path_utf8, unsigned short mode) +{ wchar_t *path_utf16 = utf8_to_utf16(sanitized_path(path_utf8)); if (path_utf16 == NULL) { errno = ENOMEM; @@ -635,32 +711,34 @@ w32_mkdir(const char *path_utf8, unsigned short mode) { free(path_utf16); return -1; } - + mode_t curmask = _umask(0); _umask(curmask); - + returnStatus = _wchmod(path_utf16, mode & ~curmask & (_S_IREAD | _S_IWRITE)); free(path_utf16); - + return returnStatus; } int -w32_stat(const char *path, struct w32_stat *buf) { +w32_stat(const char *path, struct w32_stat *buf) +{ return fileio_stat(sanitized_path(path), (struct _stat64*)buf); } -// if file is symbolic link, copy its link into "link" . -int +/* if file is symbolic link, copy its link into "link" */ +int readlink(const char *path, char *link, int linklen) { strcpy_s(link, linklen, sanitized_path(path)); return 0; } -// convert forward slash to back slash +/* convert forward slash to back slash */ void -convertToBackslash(char *str) { +convertToBackslash(char *str) +{ while (*str) { if (*str == '/') *str = '\\'; @@ -668,9 +746,10 @@ convertToBackslash(char *str) { } } -// convert back slash to forward slash -void -convertToForwardslash(char *str) { +/* convert back slash to forward slash */ +void +convertToForwardslash(char *str) +{ while (*str) { if (*str == '\\') *str = '/'; @@ -683,131 +762,90 @@ convertToForwardslash(char *str) { * path to produce a canonicalized absolute pathname. */ char * -realpath(const char *path, char resolved[PATH_MAX]) { +realpath(const char *path, char resolved[PATH_MAX]) +{ char tempPath[PATH_MAX]; - - if ((path[0] == '/') && path[1] && (path[2] == ':')) { - strncpy(resolved, path + 1, strlen(path)); // skip the first '/' - } else { + + if ((path[0] == '/') && path[1] && (path[2] == ':')) + strncpy(resolved, path + 1, strlen(path)); /* skip the first '/' */ + else strncpy(resolved, path, strlen(path) + 1); - } - if ((resolved[0]) && (resolved[1] == ':') && (resolved[2] == '\0')) { // make "x:" as "x:\\" + if ((resolved[0]) && (resolved[1] == ':') && (resolved[2] == '\0')) { /* make "x:" as "x:\\" */ resolved[2] = '\\'; resolved[3] = '\0'; } if (_fullpath(tempPath, resolved, PATH_MAX) == NULL) return NULL; - + convertToForwardslash(tempPath); - resolved[0] = '/'; // will be our first slash in /x:/users/test1 format + resolved[0] = '/'; /* will be our first slash in /x:/users/test1 format */ strncpy(resolved + 1, tempPath, sizeof(tempPath) - 1); return resolved; } char* -sanitized_path(const char *path) { +sanitized_path(const char *path) +{ static char newPath[PATH_MAX] = { '\0', }; if (path[0] == '/' && path[1]) { if (path[2] == ':') { - if (path[3] == '\0') { // make "/x:" as "x:\\" + if (path[3] == '\0') { /* make "/x:" as "x:\\" */ strncpy(newPath, path + 1, strlen(path) - 1); newPath[2] = '\\'; newPath[3] = '\0'; return newPath; - } else { - return (char *)(path + 1); // skip the first "/" - } - } - } + } else + return (char *)(path + 1); /* skip the first "/" */ + } + } - return (char *)path; + return (char *)path; } -// 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; +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) - { + 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 - // + } 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) - { + + 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) - { + if (*plen >= msReparseInfo->MountPointReparseBuffer.SubstituteNameLength) { reparseData = (PBYTE)&msReparseInfo->SymbolicLinkReparseBuffer.PathBuffer; WCHAR temp[1024]; wcsncpy_s(temp, 1024, @@ -815,9 +853,7 @@ ResolveLink(wchar_t * tLink, wchar_t *ret, DWORD * plen, DWORD Flags) { (size_t)msReparseInfo->MountPointReparseBuffer.SubstituteNameLength); temp[msReparseInfo->MountPointReparseBuffer.SubstituteNameLength] = 0; swprintf_s(ret, *plen, L"%ls", &temp[4]); - } - else - { + } else { swprintf_s(ret, *plen, L"%ls", tLink); return FALSE; } @@ -828,16 +864,16 @@ ResolveLink(wchar_t * tLink, wchar_t *ret, DWORD * plen, DWORD Flags) { } } } - } - else { + } else swprintf_s(ret, *plen, L"%ls", tLink); - } CloseHandle(fileHandle); return TRUE; } -int statvfs(const char *path, struct statvfs *buf) { +int +statvfs(const char *path, struct statvfs *buf) +{ DWORD sectorsPerCluster; DWORD bytesPerSector; DWORD freeClusters; @@ -845,8 +881,7 @@ int statvfs(const char *path, struct statvfs *buf) { wchar_t* path_utf16 = utf8_to_utf16(sanitized_path(path)); if (GetDiskFreeSpaceW(path_utf16, §orsPerCluster, &bytesPerSector, - &freeClusters, &totalClusters) == TRUE) - { + &freeClusters, &totalClusters) == TRUE) { debug3("path : [%s]", path); debug3("sectorsPerCluster : [%lu]", sectorsPerCluster); debug3("bytesPerSector : [%lu]", bytesPerSector); @@ -868,74 +903,25 @@ int statvfs(const char *path, struct statvfs *buf) { free(path_utf16); return 0; - } - else - { - debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", - path, GetLastError()); + } else { + debug3("ERROR: Cannot get free space for [%s]. Error code is : %d.\n", path, GetLastError()); free(path_utf16); return -1; } } -int fstatvfs(int fd, struct statvfs *buf) { +int +fstatvfs(int fd, struct statvfs *buf) +{ errno = ENOTSUP; return -1; } -/* w32_strerror start */ -/* Windows CRT defines error string messages only till 43 in errno.h*/ -/* This is an extended list that defines messages for EADDRINUSE through EWOULDBLOCK*/ -char* _sys_errlist_ext[] = { - "Address already in use", // EADDRINUSE 100 - "Address not available", // EADDRNOTAVAIL 101 - "Address family not supported", // EAFNOSUPPORT 102 - "Connection already in progress", // EALREADY 103 - "Bad message", // EBADMSG 104 - "Operation canceled", // ECANCELED 105 - "Connection aborted", // ECONNABORTED 106 - "Connection refused", // ECONNREFUSED 107 - "Connection reset", // ECONNRESET 108 - "Destination address required", // EDESTADDRREQ 109 - "Host is unreachable", // EHOSTUNREACH 110 - "Identifier removed", // EIDRM 111 - "Operation in progress", // EINPROGRESS 112 - "Socket is connected", // EISCONN 113 - "Too many levels of symbolic links", // ELOOP 114 - "Message too long", // EMSGSIZE 115 - "Network is down", // ENETDOWN 116 - "Connection aborted by network", // ENETRESET 117 - "Network unreachable", // ENETUNREACH 118 - "No buffer space available", // ENOBUFS 119 - "No message is available on the STREAM head read queue", // ENODATA 120 - "Link has been severed", // ENOLINK 121 - "No message of the desired type", // ENOMSG 122 - "Protocol not available", // ENOPROTOOPT 123 - "No STREAM resources", // ENOSR 124 - "Not a STREAM", // ENOSTR 125 - "The socket is not connected", // ENOTCONN 126 - "enotecoverable", // ENOTRECOVERABLE 127 - "Not a socket", // ENOTSOCK 128 - "Operation not supported", // ENOTSUP 129 - "Operation not supported on socket", // EOPNOTSUPP 130 - "eother", // EOTHER 131 - "Value too large to be stored in data type", // EOVERFLOW 132 - "eownerdead", // EOWNERDEAD 133 - "Protocol error", // EPROTO 134 - "Protocol not supported", // EPROTONOSUPPORT 135 - "Protocol wrong type for socket", // EPROTOTYPE 136 - "Timer expired", // ETIME 137 - "Connection timed out", // ETIMEDOUT 138 - "Text file busy", // ETXTBSY 139 - "Operation would block" // EWOULDBLOCK 140 -}; - char * -w32_strerror(int errnum) { +w32_strerror(int errnum) +{ if (errnum >= EADDRINUSE && errnum <= EWOULDBLOCK) return _sys_errlist_ext[errnum - EADDRINUSE]; return strerror(errnum); } - -/* w32_strerror end */ \ No newline at end of file diff --git a/contrib/win32/win32compat/no-ops.c b/contrib/win32/win32compat/no-ops.c index 48db70c9..3976e069 100644 --- a/contrib/win32/win32compat/no-ops.c +++ b/contrib/win32/win32compat/no-ops.c @@ -31,23 +31,28 @@ #include "inc\sys\types.h" /* uuidswap.c defs */ -void temporarily_use_uid(struct passwd *pw){ - return; +void +temporarily_use_uid(struct passwd *pw) +{ + return; } void -permanently_drop_suid(uid_t uid) { - return; +permanently_drop_suid(uid_t uid) +{ + return; } void -restore_uid(void) { - return; +restore_uid(void) +{ + return; } void -permanently_set_uid(struct passwd *pw) { - return; +permanently_set_uid(struct passwd *pw) +{ + return; } @@ -56,74 +61,63 @@ int muxserver_sock = -1; typedef struct Channel Channel; unsigned int muxclient_command = 0; void -muxserver_listen(void){ - return; +muxserver_listen(void) +{ + return; } void -mux_exit_message(Channel *c, int exitval) { - return; +mux_exit_message(Channel *c, int exitval) +{ + return; } void -mux_tty_alloc_failed(Channel *c) { - return; +mux_tty_alloc_failed(Channel *c) +{ + return; } void -muxclient(const char *path) { - return; +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; +innetgr(const char *netgroup, const char *host, const char *user, const char *domain) +{ + return -1; } int -ga_match(char * const *groups, int n) { - return -1; +chroot(const char *path) +{ + return -1; } int -ga_match_pattern_list(const char *group_pattern) { - return -1; +initgroups(const char *user, gid_t group) +{ + 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; +setgroups(gid_t group, char* name) +{ + return 0; } int -setsid(void) { - return 0; +setsid(void) +{ + return 0; } -int startup_handler(void) { +int +startup_handler(void) +{ return 0; } + diff --git a/contrib/win32/win32compat/pwd.c b/contrib/win32/win32compat/pwd.c index 5f072e06..7accd818 100644 --- a/contrib/win32/win32compat/pwd.c +++ b/contrib/win32/win32compat/pwd.c @@ -36,6 +36,7 @@ #include #define SECURITY_WIN32 #include + #include "inc\pwd.h" #include "inc\grp.h" #include "inc\utf.h" @@ -45,237 +46,279 @@ static struct passwd pw; static char* pw_shellpath = NULL; #define SHELL_HOST "\\ssh-shellhost.exe" + 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; +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); +reset_pw() +{ + initialize_pw(); + if (pw.pw_name) + free(pw.pw_name); + if (pw.pw_dir) + free(pw.pw_dir); + if (pw.pw_sid) + free(pw.pw_sid); + pw.pw_name = NULL; + pw.pw_dir = NULL; + pw.pw_sid = NULL; } 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[PATH_MAX], profile_home[PATH_MAX]; - HKEY reg_key = 0; - int tmp_len = PATH_MAX; - 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) { - NET_API_STATUS status; - if ((status = NetUserGetInfo(udom_utf16, uname_utf16, 23, &user_info)) != NERR_Success) { - debug("NetUserGetInfo() failed with error: %d \n", status); - - DWORD dsStatus; - if ((dsStatus = DsGetDcNameW(NULL, udom_utf16, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdc)) == ERROR_SUCCESS) { - if ((status = NetUserGetInfo(pdc->DomainControllerName, uname_utf16, 23, &user_info)) != NERR_Success) { - debug("NetUserGetInfo() with domainController failed with error: %d \n", status); - - if (ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { - error("ConvertSidToStringSidW() failed with error: %d\n", GetLastError()); - - errno = ENOMEM; //?? - goto done; - } - } - } else { - error("DsGetDcNameW() failed with error: %d \n", dsStatus); - errno = ENOMEM; //?? - goto done; - } - } else { - if (ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { - error("NetUserGetInfo() Succeded but ConvertSidToStringSidW() failed with error: %d\n", GetLastError()); - errno = ENOMEM; //?? - goto done; - } - } - - user_sid = user_sid_local; - } - - if (swprintf(reg_path, PATH_MAX, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", user_sid) == PATH_MAX || - 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, PATH_MAX); - - 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; +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, *uname_upn = NULL, *udom_utf8 = NULL, *pw_home_utf8 = NULL, *user_sid_utf8 = NULL; + LPBYTE user_info = NULL; + LPWSTR user_sid_local = NULL; + wchar_t reg_path[PATH_MAX], profile_home[PATH_MAX]; + HKEY reg_key = 0; + int tmp_len = PATH_MAX; + PDOMAIN_CONTROLLER_INFOW pdc = NULL; + DWORD dsStatus, uname_upn_len = 0;; + + 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) { + NET_API_STATUS status; + if ((status = NetUserGetInfo(udom_utf16, uname_utf16, 23, &user_info)) != NERR_Success) { + debug("NetUserGetInfo() failed with error: %d for user: %ls and domain: %ls \n", status, uname_utf16, udom_utf16); + + if ((dsStatus = DsGetDcNameW(NULL, udom_utf16, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED, &pdc)) != ERROR_SUCCESS) { + error("DsGetDcNameW() failed with error: %d \n", dsStatus); + errno = ENOENT; + goto done; + } + + if ((status = NetUserGetInfo(pdc->DomainControllerName, uname_utf16, 23, &user_info)) != NERR_Success) { + debug("NetUserGetInfo() with domainController: %ls failed with error: %d \n", pdc->DomainControllerName, status); + errno = ENOENT; + goto done; + } + } + + if (ConvertSidToStringSidW(((LPUSER_INFO_23)user_info)->usri23_user_sid, &user_sid_local) == FALSE) { + debug("NetUserGetInfo() Succeded but ConvertSidToStringSidW() failed with error: %d\n", GetLastError()); + errno = ENOENT; + goto done; + } + + user_sid = user_sid_local; + } + + /* if one of below fails, set profile path to Windows directory */ + if (swprintf(reg_path, PATH_MAX, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%ls", user_sid) == PATH_MAX || + 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, PATH_MAX); + + if ((uname_utf8 = utf16_to_utf8(uname_utf16)) == NULL || + (udom_utf16 && (udom_utf8 = utf16_to_utf8(udom_utf16)) == NULL) || + (pw_home_utf8 = utf16_to_utf8(profile_home)) == NULL || + (user_sid_utf8 = utf16_to_utf8(user_sid)) == NULL) { + errno = ENOMEM; + goto done; + } + + uname_upn_len = strlen(uname_utf8) + 1; + if (udom_utf8) + uname_upn_len += strlen(udom_utf8) + 1; + + if ((uname_upn = malloc(uname_upn_len)) == NULL) { + errno = ENOMEM; + goto done; + } + + memcpy(uname_upn, uname_utf8, strlen(uname_utf8) + 1); + if (udom_utf8) { + /* TODO - get domain FQDN */ + uname_upn[strlen(uname_utf8)] = '@'; + memcpy(uname_upn + strlen(uname_utf8) + 1, udom_utf8, strlen(udom_utf8) + 1); + } + pw.pw_name = uname_upn; + uname_upn = NULL; + pw.pw_dir = pw_home_utf8; + pw_home_utf8 = NULL; + pw.pw_sid = user_sid_utf8; + user_sid_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; + if (user_utf16) + free(user_utf16); + if (uname_utf8) + free(uname_utf8); + if (uname_upn) + free(uname_upn); + if (udom_utf8) + free(udom_utf8); + if (pw_home_utf8) + free(pw_home_utf8); + if (user_sid_utf8) + free(user_sid_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); +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); +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; + 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) { +char * +group_from_gid(gid_t gid, int nogroup) +{ return "-"; } -char *user_from_uid(uid_t uid, int nouser) { +char * +user_from_uid(uid_t uid, int nouser) +{ return "-"; } uid_t -getuid(void) { +getuid(void) +{ return 0; } gid_t -getgid(void) { +getgid(void) +{ return 0; } uid_t -geteuid(void) { +geteuid(void) +{ return 0; } gid_t -getegid(void) { +getegid(void) +{ return 0; } int -setuid(uid_t uid) { +setuid(uid_t uid) +{ return 0; } int -setgid(gid_t gid) { +setgid(gid_t gid) +{ return 0; } int -seteuid(uid_t uid) { +seteuid(uid_t uid) +{ return 0; } int -setegid(gid_t gid) { +setegid(gid_t gid) +{ return 0; } diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c index cb869677..de8ae2f3 100644 --- a/contrib/win32/win32compat/shell-host.c +++ b/contrib/win32/win32compat/shell-host.c @@ -1,41 +1,43 @@ /* -* 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. -*/ + * 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) 2017 Microsoft Corp. + * All rights reserved + * + * Shell-host is responsible for handling all the interactive and non-interactive cmds. + * + * 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 "misc_internal.h" +#include "inc\utf.h" #define MAX_CONSOLE_COLUMNS 9999 #define MAX_CONSOLE_ROWS 9999 @@ -51,47 +53,45 @@ #define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 #endif -typedef BOOL (WINAPI *__t_SetCurrentConsoleFontEx)( - _In_ HANDLE hConsoleOutput, - _In_ BOOL bMaximumWindow, - _In_ PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx - ); +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 - ); +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 - ); +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; + DWORD event; + HWND hwnd; + LONG idObject; + LONG idChild; + void* prior; + void* next; } consoleEvent; -struct key_translation -{ - char incoming[5]; - int vk; - char outgoing[1]; +struct key_translation { + char incoming[5]; + int vk; + char outgoing[1]; } key_translation; -struct key_translation keys[] = { +struct key_translation keys[] = { { "\x1b", VK_ESCAPE, "\x1b" }, { "\r", VK_RETURN, "\r" }, { "\b", VK_BACK, "\b" }, @@ -171,762 +171,689 @@ 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_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) \ +#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) +/* + * This function will handle the console keystrokes. + */ +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); + 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; +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 (bUseAnsiEmulation) - WriteFile(hInput, "\n", 1, &wr, NULL); + if (nKey == index) + for(int i=0; i < strlen(ansikey); i++) + SendKeyStroke(child_in, 0, ansikey[i]); } -void SendClearScreen(HANDLE hInput) { - DWORD wr = 0; +/* + * VT output routines + */ +void +SendLF(HANDLE hInput) +{ + DWORD wr = 0; - if (bUseAnsiEmulation) - WriteFile(hInput, "\033[2J", 4, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\n", 1, &wr, NULL); } -void SendClearScreenFromCursor(HANDLE hInput) { - DWORD wr = 0; +void +SendClearScreen(HANDLE hInput) +{ + DWORD wr = 0; - if (bUseAnsiEmulation) - WriteFile(hInput, "\033[1J", 4, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[2J", 4, &wr, NULL); } -void SendHideCursor(HANDLE hInput) { - DWORD wr = 0; +void +SendClearScreenFromCursor(HANDLE hInput) +{ + DWORD wr = 0; - if (bUseAnsiEmulation) - WriteFile(hInput, "\033[?25l", 6, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[1J", 4, &wr, NULL); } -void SendShowCursor(HANDLE hInput) { - DWORD wr = 0; +void +SendHideCursor(HANDLE hInput) +{ + DWORD wr = 0; - if (bUseAnsiEmulation) - WriteFile(hInput, "\033[?25h", 6, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[?25l", 6, &wr, NULL); } -void SendCursorPositionRequest(HANDLE hInput) { - DWORD wr = 0; +void +SendShowCursor(HANDLE hInput) +{ + DWORD wr = 0; - if (bUseAnsiEmulation) - WriteFile(hInput, "\033[6n", 4, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[?25h", 6, &wr, NULL); } -void SendSetCursor(HANDLE hInput, int X, int Y) { - - DWORD wr = 0; - DWORD out = 0; - - char formatted_output[255]; +void +SendCursorPositionRequest(HANDLE hInput) +{ + DWORD wr = 0; - out = _snprintf_s(formatted_output, sizeof(formatted_output), _TRUNCATE, "\033[%d;%dH", Y, X); - if (bUseAnsiEmulation) - WriteFile(hInput, formatted_output, out, &wr, NULL); + if (bUseAnsiEmulation) + WriteFile(hInput, "\033[6n", 4, &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); +void +SendSetCursor(HANDLE hInput, int X, int Y) +{ + DWORD wr = 0; + DWORD out = 0; + char formatted_output[255]; - if (bUseAnsiEmulation) - WriteFile(hInput, formatted_output, out, &wr, NULL); - } - // Not supporting the [S at the moment. + out = _snprintf_s(formatted_output, sizeof(formatted_output), _TRUNCATE, "\033[%d;%dH", Y, X); + if (bUseAnsiEmulation) + WriteFile(hInput, formatted_output, out, &wr, NULL); } -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 +SendVerticalScroll(HANDLE hInput, int lines) +{ + DWORD wr = 0; + DWORD out = 0; + char formatted_output[255]; + + LONG vn = abs(lines); + /* Not supporting the [S at the moment. */ + if (lines > 0) { + out = snprintf(formatted_output, sizeof(formatted_output), "\033[%dT", vn); + + 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; +void +SendHorizontalScroll(HANDLE hInput, int cells) +{ + DWORD wr = 0; + DWORD out = 0; + char formatted_output[255]; - char formatted_output[2048]; + out = snprintf(formatted_output, sizeof(formatted_output), "\033[%dG", cells); - static WORD pattributes = 0; + if (bUseAnsiEmulation) + WriteFile(hInput, formatted_output, out, &wr, NULL); +} - USHORT Color = 0; +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; + size_t SizeLeft; - if (!character) - return; + if (!character) + return; - Next = formatted_output; - SizeLeft = sizeof formatted_output; + Next = formatted_output; + SizeLeft = sizeof formatted_output; - // - // Handle the foreground intensity - // - if ((attributes & FOREGROUND_INTENSITY) != 0) { + /* Handle the foreground intensity */ + if ((attributes & FOREGROUND_INTENSITY) != 0) Color = 1; - } - else { + 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); + /* Handle the background intensity */ + if ((attributes & BACKGROUND_INTENSITY) != 0) + Color = 1; + else + Color = 39; 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); + /* Handle the underline */ + if ((attributes & COMMON_LVB_UNDERSCORE) != 0) + Color = 4; + else + Color = 24; 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); + /* Handle reverse video */ + if ((attributes & COMMON_LVB_REVERSE_VIDEO) != 0) + Color = 7; + else + Color = 27; - // 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; - } + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); - srWindowRect.Right = (SHORT)(min(inputSi.dwXCountChars, coordScreen.X) - 1); - srWindowRect.Bottom = (SHORT)(min(inputSi.dwYCountChars, coordScreen.Y) - 1); - srWindowRect.Left = srWindowRect.Top = (SHORT)0; + /* Add background and foreground colors to buffer. */ + Color = 30 + + 4 * ((attributes & FOREGROUND_BLUE) != 0) + + 2 * ((attributes & FOREGROUND_GREEN) != 0) + + 1 * ((attributes & FOREGROUND_RED) != 0); - /// Define the new console buffer size to be the maximum possible. - coordScreen.X = 100; - coordScreen.Y = 9999; + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); - if (SetConsoleWindowInfo(child_out, TRUE, &srWindowRect)) { + Color = 40 + + 4 * ((attributes & BACKGROUND_BLUE) != 0) + + 2 * ((attributes & BACKGROUND_GREEN) != 0) + + 1 * ((attributes & BACKGROUND_RED) != 0); - bSuccess = SetConsoleScreenBufferSize(child_out, coordScreen); - } - else { - if (SetConsoleScreenBufferSize(child_out, coordScreen)) { + StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, ";%u", Color); - bSuccess = SetConsoleWindowInfo(child_out, TRUE, &srWindowRect); - } + 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); + } - bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); + pattributes = attributes; } -// End of VT output routines - -DWORD WINAPI MonitorChild(_In_ LPVOID lpParameter) { - WaitForSingleObject(child, INFINITE); - GetExitCodeProcess(child, &child_exit_code); - PostThreadMessage(hostThreadId, WM_APPEXIT, 0, 0); - return 0; -} +void +SendBuffer(HANDLE hInput, CHAR_INFO *buffer, DWORD bufferSize) +{ + if (bufferSize <= 0) + return; -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; + for (DWORD i = 0; i < bufferSize; i++) + SendCharacter(hInput, buffer[i].Attributes, buffer[i].Char.UnicodeChar); } -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); - } +void +CalculateAndSetCursor(HANDLE hInput, UINT aboveTopLine, UINT viewPortHeight, UINT x, UINT y) +{ - return 0; + SendSetCursor(pipe_out, x + 1, y + 1); + currentLine = y; } -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; +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; + } - // New tail points to old tail - current->prior = tail; - current->next = NULL; + srWindowRect.Right = (SHORT)(min(inputSi.dwXCountChars, coordScreen.X) - 1); + srWindowRect.Bottom = (SHORT)(min(inputSi.dwYCountChars, coordScreen.Y) - 1); + srWindowRect.Left = srWindowRect.Top = (SHORT)0; - // Update the tail pointer to the new - // last event - tail = current; - } - } + /* Define the new console buffer size to be the maximum possible */ + coordScreen.X = 100; + coordScreen.Y = 9999; - LeaveCriticalSection(&criticalSection); + if (SetConsoleWindowInfo(child_out, TRUE, &srWindowRect)) + bSuccess = SetConsoleScreenBufferSize(child_out, coordScreen); + else { + if (SetConsoleScreenBufferSize(child_out, coordScreen)) + bSuccess = SetConsoleWindowInfo(child_out, TRUE, &srWindowRect); + } - return; + bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); } -DWORD WINAPI ProcessPipes(LPVOID p) { - - BOOL ret; - DWORD dwStatus; +DWORD WINAPI +MonitorChild(_In_ LPVOID lpParameter) +{ + WaitForSingleObject(child, INFINITE); + GetExitCodeProcess(child, &child_exit_code); + PostThreadMessage(hostThreadId, WM_APPEXIT, 0, 0); + return 0; +} - /* process data from pipe_in and route appropriately */ - while (1) { - char buf[128]; - ZeroMemory(buf, 128); +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); - DWORD rd = 0, wr = 0, i = -1; + /* Set cursor location based on the reported location from the message */ + CalculateAndSetCursor(pipe_out, ViewPortY, viewPortHeight, wX, wY); - GOTO_CLEANUP_ON_FALSE(ReadFile(pipe_in, buf, 128, &rd, NULL)); + /* Send the one character. Note that a CR doesn't end up here */ + SendCharacter(pipe_out, wAttributes, chUpdate); - bStartup = FALSE; + 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; + } + } - while (++i < rd) { + ZeroMemory(&consoleInfo, sizeof(consoleInfo)); + consoleInfo.cbSize = sizeof(consoleInfo); + GetConsoleScreenBufferInfoEx(child_out, &consoleInfo); - INPUT_RECORD ir; + return ERROR_SUCCESS; +} - if (buf[i] == 3) {/*Ctrl+C - Raise Ctrl+C*/ - GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); - continue; - } +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; +} - 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); +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); +} - ir.Event.KeyEvent.bKeyDown = FALSE; - WriteConsoleInputA(child_in, &ir, 1, &wr); - } - else { - ProcessIncomingKeys(buf); - break; - } - } - } +DWORD WINAPI +ProcessPipes(LPVOID p) +{ + BOOL ret; + DWORD dwStatus; + char buf[128]; + + /* process data from pipe_in and route appropriately */ + while (1) { + ZeroMemory(buf, 128); + DWORD rd = 0, wr = 0, i = -1; + + GOTO_CLEANUP_ON_FALSE(ReadFile(pipe_in, buf, 127, &rd, NULL)); /* read bufsize-1 */ + 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; + /* pipe_in has ended */ + PostThreadMessage(hostThreadId, WM_APPEXIT, 0, 0); + dwStatus = GetLastError(); + return 0; } -void CALLBACK ConsoleEventProc(HWINEVENTHOOK hWinEventHook, +void CALLBACK +ConsoleEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, @@ -934,377 +861,362 @@ void CALLBACK ConsoleEventProc(HWINEVENTHOOK hWinEventHook, DWORD dwEventThread, DWORD dwmsEventTime) { - QueueEvent(event, hwnd, idObject, idChild); + QueueEvent(event, hwnd, idObject, idChild); } -DWORD ProcessMessages(void* p) +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); - } - } + 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; + 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) +int +start_with_pty(wchar_t *command) +{ + 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'; GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe")); + + if (command) { + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, command)); + } - ac--; - av++; - if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); - while (ac) { - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, *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)) - { - if (GetExitCodeProcess(pi.hProcess, &child_exit_code) && child_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); + 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)) { + if (GetExitCodeProcess(pi.hProcess, &child_exit_code) && child_exit_code != STILL_ACTIVE) + break; + Sleep(100); + } -cleanup: - dwStatus = GetLastError(); + /* monitor child exist */ + child = pi.hProcess; + monitor_thread = CreateThread(NULL, 0, MonitorChild, NULL, 0, NULL); + if (monitor_thread == INVALID_HANDLE_VALUE) + goto cleanup; - DeleteCriticalSection(&criticalSection); + /* disable Ctrl+C hander in this process*/ + SetConsoleCtrlHandler(NULL, TRUE); - 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); + io_thread = CreateThread(NULL, 0, ProcessPipes, NULL, 0, NULL); + if (io_thread == INVALID_HANDLE_VALUE) + goto cleanup; - FreeConsole(); + ux_thread = CreateThread(NULL, 0, ProcessEventQueue, NULL, 0, NULL); + if (ux_thread == INVALID_HANDLE_VALUE) + goto cleanup; - return child_exit_code; + 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 child_exit_code; } HANDLE child_pipe_read; HANDLE child_pipe_write; -DWORD WINAPI MonitorChild_nopty( - _In_ LPVOID lpParameter - ) { - WaitForSingleObject(child, INFINITE); + +DWORD WINAPI +MonitorChild_nopty( _In_ LPVOID lpParameter) +{ + WaitForSingleObject(child, INFINITE); GetExitCodeProcess(child, &child_exit_code); - CloseHandle(pipe_in); - //printf("XXXX CHILD PROCESS DEAD XXXXX"); - return 0; + CloseHandle(pipe_in); + 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_CMD_LEN, L"cmd.exe")); - ac -= 2; - av += 2; - if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); - while (ac) { - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, *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++; - } - } +int +start_withno_pty(wchar_t *command) +{ + 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_CMD_LEN, L"cmd.exe")); + if (command) { + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, command)); + } + 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 child_exit_code; + if (child != INVALID_HANDLE_VALUE) + TerminateProcess(child, 0); + if (monitor_thread != INVALID_HANDLE_VALUE) + WaitForSingleObject(monitor_thread, INFINITE); + + return child_exit_code; } -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); +int b64_pton(char const *src, u_char *target, size_t targsize); + +int +wmain(int ac, wchar_t **av) +{ + int pty_requested = 0; + wchar_t *cmd = NULL, *cmd_b64 = NULL; + { + /* create job to hold all child processes */ + 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) || (ac == 2 && wcscmp(av[1], L"-nopty"))) { + pty_requested = 1; + cmd_b64 = ac == 2? av[1] : NULL; + } else if (ac <= 3 && wcscmp(av[1], L"-nopty") == 0) + cmd_b64 = ac == 3? av[2] : NULL; + else { + printf("ssh-shellhost received unexpected input arguments"); + return -1; + } + + /* decode cmd_b64*/ + if (cmd_b64) { + char *cmd_b64_utf8, *cmd_utf8; + if ((cmd_b64_utf8 = utf16_to_utf8(cmd_b64)) == NULL || + /* strlen(b64) should be sufficient for decoded length */ + (cmd_utf8 = malloc(strlen(cmd_b64_utf8))) == NULL || + b64_pton(cmd_b64_utf8, cmd_utf8, strlen(cmd_b64_utf8)) == -1 || + (cmd = utf8_to_utf16(cmd_utf8)) == NULL) { + printf("ssh-shellhost encountered an internal error while decoding base64 cmdline"); + return -1; + } + free(cmd_b64_utf8); + free(cmd_utf8); + } + + if (pty_requested) + return start_with_pty(cmd); + else + return start_withno_pty(cmd); } \ No newline at end of file diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c index ab567a0d..04ff903c 100644 --- a/contrib/win32/win32compat/signal.c +++ b/contrib/win32/win32compat/signal.c @@ -28,10 +28,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "w32fd.h" #include +#include "w32fd.h" #include "signal_internal.h" #include "inc\signal.h" + #undef signal #undef raise #undef SIGINT @@ -48,30 +49,27 @@ /* pending signals to be processed */ sigset_t pending_signals; - /* signal handler table*/ sighandler_t sig_handlers[W32_SIGMAX]; +extern struct _children children; -static VOID CALLBACK -sigint_APCProc( - _In_ ULONG_PTR dwParam - ) { +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 - ) { +sigterm_APCProc(_In_ ULONG_PTR dwParam) +{ debug3("SIGTERM APCProc()"); sigaddset(&pending_signals, W32_SIGTERM); } static VOID CALLBACK -sigtstp_APCProc( - _In_ ULONG_PTR dwParam - ) { +sigtstp_APCProc(_In_ ULONG_PTR dwParam) +{ debug3("SIGTSTP APCProc()"); sigaddset(&pending_signals, W32_SIGTSTP); } @@ -100,48 +98,50 @@ native_sig_handler(DWORD dwCtrlType) } static VOID CALLBACK -sigwinch_APCProc( - _In_ ULONG_PTR dwParam - ) { +sigwinch_APCProc(_In_ ULONG_PTR dwParam) +{ debug3("SIGTERM APCProc()"); sigaddset(&pending_signals, W32_SIGWINCH); } - void -queue_terminal_window_change_event() { +queue_terminal_window_change_event() +{ QueueUserAPC(sigwinch_APCProc, main_thread, (ULONG_PTR)NULL); } -void -sw_init_signal_handler_table() { - int i; - +void +sw_init_signal_handler_table() +{ SetConsoleCtrlHandler(native_sig_handler, TRUE); sigemptyset(&pending_signals); /* this automatically sets all to W32_SIG_DFL (0)*/ memset(sig_handlers, 0, sizeof(sig_handlers)); } -extern struct _children children; +sighandler_t +mysignal(int signum, sighandler_t handler) { + return w32_signal(signum, handler); +} -sighandler_t -w32_signal(int signum, sighandler_t handler) { +sighandler_t +w32_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]; + prev = sig_handlers[signum]; sig_handlers[signum] = handler; return prev; } -int -w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { +int +w32_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"); @@ -150,8 +150,9 @@ w32_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { -int -w32_raise(int sig) { +int +w32_raise(int sig) +{ debug("raise sig:%d", sig); if (sig == W32_SIGSEGV) return raise(SIGSEGV); /* raise native exception handler*/ @@ -170,7 +171,7 @@ w32_raise(int sig) { /* 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: @@ -184,8 +185,9 @@ w32_raise(int sig) { } /* processes pending signals, return -1 and errno=EINTR if any are processed*/ -static int -sw_process_pending_signals() { +static int +sw_process_pending_signals() +{ sigset_t pending_tmp = pending_signals; BOOL sig_int = FALSE; /* has any signal actually interrupted */ @@ -195,7 +197,7 @@ sw_process_pending_signals() { /* check for expected signals*/ for (i = 0; i < (sizeof(exp) / sizeof(exp[0])); i++) sigdelset(&pending_tmp, exp[i]); - if (pending_tmp) { + if (pending_tmp) { /* unexpected signals queued up */ debug("process_signals() - ERROR unexpected signals in queue: %d", pending_tmp); errno = ENOTSUP; @@ -219,7 +221,7 @@ sw_process_pending_signals() { sigdelset(&pending_tmp, exp[i]); } } - + /* by now all pending signals should have been taken care of*/ if (pending_tmp) @@ -235,17 +237,17 @@ sw_process_pending_signals() { } /* - * Main wait routine used by all blocking calls. - * It wakes up on + * 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 + * - 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 + * if milli_seconds is 0, this function returns 0, its called with 0 * to execute any scheduled APCs */ -int +int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) { HANDLE all_events[MAXIMUM_WAIT_OBJECTS]; @@ -266,55 +268,49 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) 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); + 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*/ + /* woken up by event signalled + * is this due to a child process going down + */ if (live_children && ((ret - WAIT_OBJECT_0) < live_children)) { sigaddset(&pending_signals, W32_SIGCHLD); sw_child_to_zombie(ret - WAIT_OBJECT_0); } - } - else if (ret == WAIT_IO_COMPLETION) { + } else if (ret == WAIT_IO_COMPLETION) { /* APC processed due to IO or signal*/ - } - else if (ret == WAIT_TIMEOUT) { + } else if (ret == WAIT_TIMEOUT) { /* timed out */ return 0; - } - /* some other error*/ - else { + } else { /* some other error*/ errno = EOTHER; debug("ERROR: unxpected wait end: %d", ret); return -1; } - } - else { + } else { DWORD ret = SleepEx(milli_seconds, TRUE); if (ret == WAIT_IO_COMPLETION) { /* APC processed due to IO or signal*/ - } - else if (ret == 0) { + } else if (ret == 0) { /* timed out */ return 0; - } - else { //some other error + } else { /* some other error */ errno = EOTHER; debug("ERROR: unxpected SleepEx error: %d", ret); return -1; } } - if (pending_signals) { + if (pending_signals) return sw_process_pending_signals(); - } + return 0; } int -sw_initialize() { +sw_initialize() +{ memset(&children, 0, sizeof(children)); sw_init_signal_handler_table(); if (sw_init_timer() != 0) diff --git a/contrib/win32/win32compat/signal_sigalrm.c b/contrib/win32/win32compat/signal_sigalrm.c index 4f83c86c..31f55273 100644 --- a/contrib/win32/win32compat/signal_sigalrm.c +++ b/contrib/win32/win32compat/signal_sigalrm.c @@ -35,16 +35,16 @@ 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 - ) { +sigalrm_APC(_In_opt_ LPVOID lpArgToCompletionRoutine, + _In_ DWORD dwTimerLowValue, + _In_ DWORD dwTimerHighValue) +{ sigaddset(&pending_signals, W32_SIGALRM); } unsigned int -w32_alarm(unsigned int sec) { +w32_alarm(unsigned int sec) +{ LARGE_INTEGER due; ULONGLONG sec_passed; int ret = 0; @@ -59,7 +59,7 @@ w32_alarm(unsigned int sec) { return 0; } - due.QuadPart = -10000000LL; //1 sec in 100 nanosec intervals + 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)) { @@ -75,16 +75,19 @@ w32_alarm(unsigned int sec) { } timer_info.ticks_at_start = GetTickCount64(); timer_info.run_time_sec = sec; + return ret; } int -sw_init_timer() { +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 index 4ad7c932..7a43ee70 100644 --- a/contrib/win32/win32compat/signal_sigchld.c +++ b/contrib/win32/win32compat/signal_sigchld.c @@ -34,7 +34,8 @@ struct _children children; int -register_child(HANDLE child, DWORD pid) { +register_child(HANDLE child, DWORD pid) +{ DWORD first_zombie_index; debug("Register child %p pid %d, %d zombies of %d", child, pid, @@ -43,6 +44,7 @@ register_child(HANDLE child, DWORD pid) { 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]; @@ -50,26 +52,23 @@ register_child(HANDLE child, DWORD pid) { children.handles[first_zombie_index] = child; children.process_id[first_zombie_index] = pid; - } - else { + } 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) { +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)) { + if ((index >= children.num_children) || (children.num_children == 0)) { errno = EINVAL; return -1; } @@ -78,15 +77,13 @@ sw_remove_child_at_index(DWORD 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 { + } 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 { + } 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]; @@ -101,7 +98,8 @@ sw_remove_child_at_index(DWORD index) { } int -sw_child_to_zombie(DWORD index) { +sw_child_to_zombie(DWORD index) +{ DWORD last_non_zombie, zombie_pid; HANDLE zombie_handle; @@ -114,7 +112,6 @@ sw_child_to_zombie(DWORD index) { } last_non_zombie = children.num_children - children.num_zombies - 1; - if (last_non_zombie != index) { /* swap */ zombie_pid = children.process_id[index]; @@ -129,7 +126,8 @@ sw_child_to_zombie(DWORD index) { } int -w32_kill(int pid, int sig) { +w32_kill(int pid, int sig) +{ int child_index, i; if (pid == GetCurrentProcessId()) return w32_raise(sig); @@ -148,7 +146,9 @@ w32_kill(int pid, int sig) { } -int waitpid(int pid, int *status, int options) { +int +waitpid(int pid, int *status, int options) +{ DWORD index, ret, ret_id, exit_code, timeout = 0; HANDLE process = NULL; @@ -214,7 +214,7 @@ int waitpid(int pid, int *status, int options) { sw_remove_child_at_index(children.num_children - 1); return ret_id; } - + /* all children are alive. wait for one of them to exit */ timeout = INFINITE; if (options & WNOHANG) @@ -230,20 +230,19 @@ int waitpid(int pid, int *status, int options) { if (status) *status = exit_code; return ret_id; - } - else if (ret == WAIT_TIMEOUT) { + } else if (ret == WAIT_TIMEOUT) { /* TODO - assert that WNOHANG was specified*/ return 0; } - DebugBreak();//fatal + DebugBreak(); /* fatal */ return -1; } void -sw_cleanup_child_zombies() { +sw_cleanup_child_zombies() +{ int pid = 1; - while (pid > 0) { + 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 index c4ba4948..af946835 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -33,19 +33,26 @@ #include #include #include -#include "w32fd.h" #include +#include "w32fd.h" #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()) +/* 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; +}; + /* maps WSAError to errno */ -static -int errno_from_WSAError(int wsaerrno) +static int +errno_from_WSAError(int wsaerrno) { /* TODO - create a mapping table - more efficient */ switch (wsaerrno) { @@ -70,43 +77,34 @@ int errno_from_WSAError(int wsaerrno) case WSAECONNRESET: return ECONNRESET; default: - /* */ return wsaerrno - 10000; } } /* called before any other calls to socketio_ functions */ -int -socketio_initialize() { +int +socketio_initialize() +{ WSADATA wsaData = { 0 }; return WSAStartup(MAKEWORD(2, 2), &wsaData); } /* cleanup */ -int -socketio_done() { +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) { +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 */ @@ -118,18 +116,17 @@ socketio_acceptEx(struct w32_io* pio) { } 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)) + 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 { + } else { /* if overlapped io is in progress, we are good */ if (WSAGetLastError() != ERROR_IO_PENDING) { errno = errno_from_WSALastError(); @@ -142,16 +139,14 @@ socketio_acceptEx(struct w32_io* pio) { return 0; } -void -CALLBACK WSARecvCompletionRoutine( - IN DWORD dwError, - IN DWORD cbTransferred, - IN LPWSAOVERLAPPED lpOverlapped, - IN DWORD dwFlags - ) +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)); + 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) @@ -164,8 +159,9 @@ CALLBACK WSARecvCompletionRoutine( /* 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 +socketio_WSARecv(struct w32_io* pio, BOOL* completed) +{ int ret = 0; WSABUF wsabuf; DWORD recv_flags = 0; @@ -176,12 +172,9 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) { /* initialize recv buffers if needed */ wsabuf.len = INTERNAL_RECV_BUFFER_SIZE; - if (pio->read_details.buf == NULL) - { + if (pio->read_details.buf == NULL) { wsabuf.buf = malloc(wsabuf.len); - - if (!wsabuf.buf) - { + if (!wsabuf.buf) { errno = ENOMEM; debug("WSARecv - ERROR:%d, io:%p", errno, pio); return -1; @@ -189,29 +182,22 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) { pio->read_details.buf = wsabuf.buf; pio->read_details.buf_size = wsabuf.len; - } - else + } else wsabuf.buf = pio->read_details.buf; - - ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, - &WSARecvCompletionRoutine); - if (ret == 0) - { + 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) - { + } 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 { + } else { errno = errno_from_WSALastError(); debug("WSARecv - WSARecv() ERROR: io:%p %d", pio, errno); return -1; @@ -222,8 +208,9 @@ socketio_WSARecv(struct w32_io* pio, BOOL* completed) { } /* implements socket() */ -struct w32_io* -socketio_socket(int domain, int type, int protocol) { +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; @@ -244,20 +231,20 @@ socketio_socket(int domain, int type, int protocol) { 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; \ +#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) || +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 { @@ -268,26 +255,30 @@ socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optv } /* implements getsockopt() */ -int -socketio_getsockopt(struct w32_io* pio, int level, int optname, char* optval, int* optlen) { +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) { +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) { +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) { +int +socketio_listen(struct w32_io* pio, int backlog) +{ struct acceptEx_context* context; if (SOCKET_ERROR == listen(pio->sock, backlog)) { @@ -313,8 +304,7 @@ socketio_listen(struct w32_io* pio, int backlog) { SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &context->lpfnAcceptEx, sizeof(context->lpfnAcceptEx), - &dwBytes, NULL, NULL)) - { + &dwBytes, NULL, NULL)) { free(context); errno = errno_from_WSALastError(); debug("listen - Ioctl1 ERROR:%d, io:%p", errno, pio); @@ -325,8 +315,7 @@ socketio_listen(struct w32_io* pio, int backlog) { SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockaddrs, sizeof(GuidGetAcceptExSockaddrs), &context->lpfnGuidGetAcceptExSockaddrs, sizeof(context->lpfnGuidGetAcceptExSockaddrs), - &dwBytes, NULL, NULL)) - { + &dwBytes, NULL, NULL)) { free(context); errno = errno_from_WSALastError(); debug("listen - Ioctl2 ERROR:%d, io:%p", errno, pio); @@ -344,24 +333,24 @@ socketio_listen(struct w32_io* pio, int backlog) { 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) { +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) { +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); @@ -375,7 +364,6 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { } /* 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 */ @@ -385,8 +373,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { if (0 != wait_for_any_event(NULL, 0, INFINITE)) return -1; } - } - else { + } else { errno = EAGAIN; debug2("recv - io is already pending, io:%p", pio); return -1; @@ -394,27 +381,24 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { } /* if we have some buffer copy it and return #bytes copied */ - if (pio->read_details.remaining) - { + 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); + 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); + 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 { + } 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; @@ -437,16 +421,14 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { } } - if (w32_io_is_blocking(pio)) - { + 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 { + } else { if (socketio_is_io_available(pio, TRUE) == FALSE) { errno = EAGAIN; debug2("recv - IO is pending, io:%p", pio); @@ -455,17 +437,15 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { } /* - * by this time we should have some bytes in internal buffer + * 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) { if (pio->read_details.error == ERROR_GRACEFUL_DISCONNECT) { /* connection is closed */ debug2("recv - connection closed(2), io:%p", pio); return 0; - } - else { + } 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); @@ -478,37 +458,32 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { 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); + 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 { + } 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 - ) +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); + 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); + debug("WSASendCB - ERROR: broken assumption, io:%p, sent:%d, remaining:%d", pio, + cbTransferred, pio->write_details.remaining); DebugBreak(); } pio->write_details.remaining -= cbTransferred; @@ -516,13 +491,13 @@ CALLBACK WSASendCompletionRoutine( } /* implementation of send() */ -int -socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { +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); @@ -536,26 +511,20 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { } /* 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)) - { + 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) { + while (pio->write_details.pending) if (wait_for_any_event(NULL, 0, INFINITE) == -1) return -1; - } - } - else { + } 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); @@ -564,11 +533,9 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { /* initialize buffers if needed */ wsabuf.len = INTERNAL_SEND_BUFFER_SIZE; - if (pio->write_details.buf == NULL) - { + if (pio->write_details.buf == NULL) { wsabuf.buf = malloc(wsabuf.len); - if (!wsabuf.buf) - { + if (!wsabuf.buf) { errno = ENOMEM; debug("send - ERROR:%d, io:%p", errno, pio); return -1; @@ -576,20 +543,16 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { pio->write_details.buf = wsabuf.buf; pio->write_details.buf_size = wsabuf.len; - } - else { + } 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); + ret = WSASend(pio->sock, &wsabuf, 1, NULL, 0, &pio->write_overlapped, &WSASendCompletionRoutine); - if (ret == 0) - { + 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; @@ -603,16 +566,13 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { /* return num of bytes written */ return wsabuf.len; - } - else { - if (WSAGetLastError() == WSA_IO_PENDING) - { + } 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)) - { + 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) @@ -626,8 +586,7 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { debug3("send - returning %d, io:%p", wsabuf.len, pio); return wsabuf.len; - } - else { + } else { errno = errno_from_WSALastError(); debug("send - WSASend() ERROR:%d, io:%p", errno, pio); return -1; @@ -636,41 +595,39 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { } /* shutdown() implementation */ -int -socketio_shutdown(struct w32_io* pio, int how) { +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) { +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); + 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) - { + 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) { + } else if (pio->internal.state == SOCK_CONNECTING) { if (pio->write_overlapped.hEvent) CloseHandle(pio->write_overlapped.hEvent); - } - else { + } else { if (pio->read_details.buf) free(pio->read_details.buf); @@ -683,20 +640,20 @@ socketio_close(struct w32_io* pio) { } /* accept() implementation */ -struct w32_io* -socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { +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; + 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) { + if (socketio_acceptEx(pio) != 0) return NULL; - } } if (w32_io_is_blocking(pio)) { @@ -705,15 +662,13 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { if (-1 == wait_for_any_event(&pio->read_overlapped.hEvent, 1, INFINITE)) return NULL; - } - else { + } 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; @@ -726,8 +681,8 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { goto on_error; } - if (0 != setsockopt(context->accept_socket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, (char*)&pio->sock, sizeof(pio->sock))) { + 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; @@ -768,8 +723,9 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { } /* initiates an async connect*/ -int -socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) { +int +socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) +{ struct sockaddr_in tmp_addr4; struct sockaddr_in6 tmp_addr6; @@ -786,22 +742,19 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) tmp_addr6.sin6_port = 0; tmp_addr = (SOCKADDR*)&tmp_addr6; tmp_addr_len = sizeof(tmp_addr6); - } - else if (name->sa_family == AF_INET) { + } 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 { + } 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)) - { + 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; @@ -810,27 +763,25 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) if (SOCKET_ERROR == WSAIoctl(pio->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &connectex_guid, sizeof(connectex_guid), &ConnectEx, sizeof(ConnectEx), - &tmp_bytes, NULL, NULL)) - { + &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)) { + 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)) { + 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 { + } else { if (WSAGetLastError() != ERROR_IO_PENDING) { CloseHandle(pio->write_overlapped.hEvent); pio->write_overlapped.hEvent = 0; @@ -846,8 +797,9 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen) } /* connect implementation */ -int -socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) { +int +socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) +{ debug3("connect - io:%p", pio); if (pio->write_details.pending == FALSE) { @@ -858,29 +810,25 @@ socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen) { 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)) + if (-1 == wait_for_any_event(&pio->write_overlapped.hEvent, 1, INFINITE)) return -1; } - } - else { + } 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) { - +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); @@ -902,69 +850,61 @@ socketio_finish_connect(struct w32_io* pio) { } /* 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) || +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; + 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 { + } else { if (pio->write_details.error) return TRUE; } - if (WSAGetOverlappedResult(pio->sock, overlapped, - &numBytes, FALSE, &flags)) + 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; - } + if (sock_listening) + pio->read_details.error = WSAGetLastError(); + else + pio->write_details.error = WSAGetLastError(); + return TRUE; + } - return FALSE; - } - else if (rd) { + return FALSE; + } else if (rd) { if (pio->read_details.remaining || pio->read_details.error) return TRUE; else return FALSE; - } - else { + } 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) { +/*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) + /* nothing to do for writes (that includes connect) */ if (!rd) return; - //listening socket - acceptEx if needed + /* listening socket - acceptEx if needed */ if (sock_state == SOCK_LISTENING) { - if (pio->read_details.pending == FALSE) + if (pio->read_details.pending == FALSE) if (socketio_acceptEx(pio) != 0) { /* set error, accept will pick it*/ pio->read_details.error = errno; @@ -973,9 +913,8 @@ socketio_on_select(struct w32_io* pio, BOOL rd) { SetEvent(pio->read_overlapped.hEvent); return; } - } - else { - //connected socket - WSARecv if needed + } 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 */ @@ -984,104 +923,103 @@ socketio_on_select(struct w32_io* pio, BOOL rd) { 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); +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); - } +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 +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; - } - } + 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; + } -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; -} + 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/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c index a9e24ec7..0fd765eb 100644 --- a/contrib/win32/win32compat/ssh-agent/authagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c @@ -38,352 +38,329 @@ #include "agent.h" #include "agent-request.h" #include "key.h" +#include "inc\utf.h" -static void +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; - } + 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; + TOKEN_PRIVILEGES tp; + HANDLE hProcToken = NULL; + LUID luid; - int exitCode = 1; + int exitCode = 1; - if (LookupPrivilegeValueA(NULL, privName, &luid) == FALSE || - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcToken) == FALSE) - goto done; + 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; + 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); + AdjustTokenPrivileges(hProcToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); done: - if (hProcToken) - CloseHandle(hProcToken); - - return; + 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); + 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"); +#define MAX_USER_LEN 64 +/* https://technet.microsoft.com/en-us/library/active-directory-maximum-limits-scalability(v=ws.10).aspx */ +#define MAX_FQDN_LEN 64 +#define MAX_PW_LEN 64 + +static HANDLE +generate_user_token(wchar_t* user_cpn) { + 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; + + domain_user = wcschr(user_cpn, L'@')? 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_cpn) * 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_cpn) * 2; + s4u_logon->ClientUpn.MaximumLength = s4u_logon->ClientUpn.Length; + s4u_logon->ClientUpn.Buffer = (WCHAR*)(s4u_logon + 1); + memcpy(s4u_logon->ClientUpn.Buffer, user_cpn, 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_cpn) + 1)*sizeof(wchar_t); + logon_info = malloc(logon_info_size); + if (logon_info == NULL) + goto done; + memcpy(logon_info, user_cpn, 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; + 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 - +/* TODO - SecureZeroMemory password */ 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; + char *user = NULL, *domain = NULL, *pwd = NULL; + size_t user_len, pwd_len; + wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp; + 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 || + user_len > MAX_USER_LEN + MAX_FQDN_LEN || + pwd_len > MAX_PW_LEN) { + debug("bad password auth request"); + goto done; + } + + if ((user_utf16 = utf8_to_utf16(user)) == NULL || + (pwd_utf16 = utf8_to_utf16(pwd)) == NULL) { + debug("out of memory"); + goto done; + } + + if ((tmp = wcschr(user_utf16, L'@') ) != NULL ) { + udom_utf16 = tmp + 1; + *tmp = L'\0'; + } + + if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) { + debug("failed to logon user: %ls domain: %ls", user_utf16, udom_utf16); + 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, user_utf16, udom_utf16); + 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; + /* 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 (user_utf16) + free(user_utf16); + if (pwd_utf16) + free(pwd_utf16); + 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("unable to verify public key for 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; + 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, restricted_token = NULL, dup_token = NULL, client_proc = NULL; + wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *tmp; + PWSTR wuser_home = NULL; + ULONG client_pid; + LUID_AND_ATTRIBUTES priv_to_delete[1]; + + user = NULL; + if (sshbuf_get_string_direct(request, &key_blob, &key_blob_len) != 0 || + sshbuf_get_cstring(request, &user, &user_len) != 0 || + user_len > MAX_USER_LEN || + 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; + } + + if ((user_utf16 = utf8_to_utf16(user)) == NULL) { + debug("out of memory"); + goto done; + } + + if ((token = generate_user_token(user_utf16)) == 0) { + debug("unable to generate token for user %ls", user_utf16); + goto done; + } + + /* for key based auth, remove SeTakeOwnershipPrivilege */ + if (LookupPrivilegeValueW(NULL, L"SeTakeOwnershipPrivilege", &priv_to_delete[0].Luid) == FALSE || + CreateRestrictedToken(token, 0, 0, NULL, 1, priv_to_delete, 0, NULL, &restricted_token) == FALSE) { + debug("unable to remove SeTakeOwnershipPrivilege privilege"); + goto done; + } + + if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, restricted_token, &wuser_home) != S_OK || + pubkey_allowed(key, user_utf16, wuser_home) != 1) { + debug("unable to verify public key for user %ls (profile:%ls)", user_utf16, 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(), restricted_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; + } + + con->auth_token = restricted_token; + restricted_token = NULL; + if ((tmp = wcschr(user_utf16, L'@')) != NULL) { + udom_utf16 = tmp + 1; + *tmp = L'\0'; + } + LoadProfile(con, user_utf16, udom_utf16); + + 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; + /* TODO Fix this hacky protocol*/ + if ((r == -1) && (sshbuf_put_u8(response, SSH_AGENT_FAILURE) == 0)) + r = 0; + + if (user) + free(user); + if (user_utf16) + free(user_utf16); + if (key) + sshkey_free(key); + if (wuser_home) + CoTaskMemFree(wuser_home); + if (client_proc) + CloseHandle(client_proc); + if (token) + CloseHandle(token); + 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; - } - + char *opn; + size_t opn_len; + if (sshbuf_get_string_direct(request, &opn, &opn_len) != 0) { + debug("invalid auth request"); + return -1; + } + + if (memcmp(opn, PUBKEY_AUTH_REQUEST, opn_len) == 0) + return process_pubkeyauth_request(request, response, con); + else if (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 index b45a0052..d9597323 100644 --- a/contrib/win32/win32compat/ssh-agent/connection.c +++ b/contrib/win32/win32compat/ssh-agent/connection.c @@ -167,9 +167,6 @@ get_con_client_type(HANDLE pipe) { return r; } -/* TODO - move this to common header*/ -#define SSH_AGENT_AUTHENTICATE 100 - static int process_request(struct agent_connection* con) { int r = -1; @@ -179,7 +176,7 @@ process_request(struct agent_connection* con) { if ((con->client_process = get_con_client_type(con->connection)) == -1) goto done; - + //Sleep(30 * 1000); request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); response = sshbuf_new(); if ((request == NULL) || (response == NULL)) diff --git a/contrib/win32/win32compat/termio.c b/contrib/win32/win32compat/termio.c index 4e554257..967b20e9 100644 --- a/contrib/win32/win32compat/termio.c +++ b/contrib/win32/win32compat/termio.c @@ -1,3 +1,40 @@ +/* + * Author: Manoj Ampalam + * read() and write() on tty using worker threads to handle + * synchronous Windows Console IO + * + * Author: Ray Hayes + * TTY/PTY support added by capturing all terminal input events + * + * Author: Balu + * Misc fixes and code cleanup + * + * Copyright (c) 2017 Microsoft Corp. + * All rights reserved + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include #include "w32fd.h" #include "tncon.h" @@ -12,12 +49,12 @@ struct io_status { DWORD transferred; DWORD error; }; - static struct io_status read_status, write_status; -static VOID CALLBACK ReadAPCProc( - _In_ ULONG_PTR dwParam - ) { +/* APC that gets queued on main thread when a sync Read completes on worker thread */ +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); @@ -30,39 +67,37 @@ static VOID CALLBACK ReadAPCProc( pio->read_overlapped.hEvent = 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; +/* Read worker thread */ +static DWORD WINAPI +ReadConsoleThread(_In_ LPVOID lpParameter) +{ + int nBytesReturned = 0; + struct w32_io* pio = (struct w32_io*)lpParameter; - 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(); - } + 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; + return 0; } +/* Initiates read on tty */ int -termio_initiate_read(struct w32_io* pio) { +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) { @@ -72,7 +107,7 @@ termio_initiate_read(struct w32_io* pio) { pio->read_details.buf_size = TERM_IO_BUF_SIZE; } - read_thread = CreateThread(NULL, 0, ReadConsoleThread, pio, 0, NULL); + 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); @@ -84,15 +119,16 @@ termio_initiate_read(struct w32_io* pio) { return 0; } -static VOID CALLBACK WriteAPCProc( - _In_ ULONG_PTR dwParam - ) { +/* APC that gets queued on main thread when a sync Write completes on worker thread */ +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*/ + /* TODO- assert that reamining is 0 by now */ pio->write_details.completed = 0; pio->write_details.pending = FALSE; WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE); @@ -100,28 +136,29 @@ static VOID CALLBACK WriteAPCProc( pio->write_overlapped.hEvent = 0; } -static DWORD WINAPI WriteThread( - _In_ LPVOID lpParameter - ) { +/* Write worker thread */ +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; + char *respbuf = NULL; + size_t resplen = 0; + DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT; debug3("TermWrite thread, io:%p", pio); - - if (in_raw_mode == 0) { + + if (in_raw_mode == 0) { /* 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 { - /* console mode */ - 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; - } + } else { + /* console mode */ + 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); @@ -132,10 +169,11 @@ static DWORD WINAPI WriteThread( return 0; } +/* Initiates write on tty */ int -termio_initiate_write(struct w32_io* pio, DWORD num_bytes) { +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; @@ -151,28 +189,27 @@ termio_initiate_write(struct w32_io* pio, DWORD num_bytes) { return 0; } - -int termio_close(struct w32_io* pio) { +/* tty close */ +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->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 + 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 index 7df7eb24..6d6d81e3 100644 --- a/contrib/win32/win32compat/tncon.c +++ b/contrib/win32/win32compat/tncon.c @@ -1,10 +1,15 @@ /* - * Author: Microsoft Corp. + * Author: Ray Hayes + * ANSI TTY Reader - Maps Windows console input events to ANSI stream + * + * Author: Balu + * Misc fixes and code cleanup * - * Copyright (c) 2015 Microsoft Corp. + * Copyright (c) 2017 Microsoft Corp. * All rights reserved * - * Microsoft openssh win32 port + * This file is responsible for console reading calls for building an emulator + * over Windows Console. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,600 +32,552 @@ * (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; - +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; + 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) +void queue_terminal_window_change_event(); + +/* + * For our case, in NetWriteString2(), we do not use socket, but write the out going data to + * a global buffer setup by ReadConsoleForTermEmul(). + */ +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++ ; + *glob_out++ = *source++; len--; glob_outlen++; } - return glob_outlen; } -BOOL DataAvailable(HANDLE h) +BOOL +DataAvailable(HANDLE h) { - DWORD dwRet = WaitForSingleObject(h, INFINITE); - if(dwRet == WAIT_OBJECT_0) - return TRUE; - - if(dwRet == WAIT_FAILED) - return FALSE; - - return FALSE; + 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) +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 ; -} - + 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: + /* FALLTHROUGH */ + 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: + break; /* NOP on these */ + 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/tnnet.c b/contrib/win32/win32compat/tnnet.c index c047414e..9763010e 100644 --- a/contrib/win32/win32compat/tnnet.c +++ b/contrib/win32/win32compat/tnnet.c @@ -1,10 +1,11 @@ /* * Author: Microsoft Corp. * - * Copyright (c) 2015 Microsoft Corp. + * Copyright (c) 2017 Microsoft Corp. * All rights reserved * - * Microsoft openssh win32 port + * This file is responsible for terminal emulation related network calls to + * invoke ANSI parsing engine. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,61 +28,52 @@ * (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) +/* + * 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; - unsigned char* pszHead = NULL; - unsigned char* pszTail = NULL; - - if (len == 0) - return len; + if (len == 0) + return len; - // Transform a single carriage return into a single linefeed before - // continuing. + /* 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. + /* + * 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; - + len = 0; return len; } diff --git a/contrib/win32/win32compat/utf.c b/contrib/win32/win32compat/utf.c new file mode 100644 index 00000000..bd93d42b --- /dev/null +++ b/contrib/win32/win32compat/utf.c @@ -0,0 +1,59 @@ +/* +* Author: Manoj Ampalam +* +* Copyright(c) 2016 Microsoft Corp. +* All rights reserved +* +* UTF8 <--> UTF16 conversion routines +* +* 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" + +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; +} + diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c index 49e7e075..3cefb5b5 100644 --- a/contrib/win32/win32compat/w32fd.c +++ b/contrib/win32/win32compat/w32fd.c @@ -67,7 +67,8 @@ void fd_table_set(struct w32_io* pio, int index); /* initializes mapping table*/ static int -fd_table_initialize() { +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; @@ -86,7 +87,8 @@ fd_table_initialize() { /* get a free slot in mapping table with least index*/ static int -fd_table_get_min_index() { +fd_table_get_min_index() +{ int min_index = 0; unsigned char* bitmap = fd_table.occupied.bitmap; unsigned char tmp; @@ -102,9 +104,7 @@ fd_table_get_min_index() { } tmp = *bitmap; - - while (tmp & 0x80) - { + while (tmp & 0x80) { tmp <<= 1; min_index++; } @@ -114,7 +114,8 @@ fd_table_get_min_index() { /* maps pio to fd (specified by index)*/ static void -fd_table_set(struct w32_io* pio, int index) { +fd_table_set(struct w32_io* pio, int index) +{ fd_table.w32_ios[index] = pio; pio->table_index = index; assert(pio->type != UNKNOWN_FD); @@ -131,19 +132,20 @@ fd_table_clear(int index) } void -w32posix_initialize() { - if ((fd_table_initialize() != 0) - || (socketio_initialize() != 0)) +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"); - } + if ((main_thread == NULL) || (sw_initialize() != 0) || w32_programdir() == NULL) { + DebugBreak(); + fatal("failed to initialize w32posix wrapper"); + } } void -w32posix_done() { +w32posix_done() +{ socketio_done(); } @@ -159,7 +161,8 @@ w32_io_is_blocking(struct w32_io* pio) * as it decides on what fds can be set. */ BOOL -w32_io_is_io_available(struct w32_io* pio, BOOL rd) { +w32_io_is_io_available(struct w32_io* pio, BOOL rd) +{ if (pio->type == SOCK_FD) return socketio_is_io_available(pio, rd); else @@ -171,7 +174,7 @@ w32_io_on_select(struct w32_io* pio, BOOL rd) { if ((pio->type == SOCK_FD)) socketio_on_select(pio, rd); - else + else fileio_on_select(pio, rd); } @@ -195,7 +198,8 @@ w32_io_on_select(struct w32_io* pio, BOOL rd) } while (0) int -w32_socket(int domain, int type, int protocol) { +w32_socket(int domain, int type, int protocol) +{ int min_index = fd_table_get_min_index(); struct w32_io* pio = NULL; @@ -216,7 +220,6 @@ w32_socket(int domain, int type, int protocol) { 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(); @@ -236,72 +239,72 @@ w32_accept(int fd, struct sockaddr* addr, int* addrlen) } int -w32_setsockopt(int fd, int level, int optname, const void* optval, int optlen) { - +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) { - +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) { - +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) { - +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) { - +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) { - +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) { - +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) { - +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) { - +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); @@ -309,7 +312,8 @@ w32_send(int fd, const void *buf, size_t len, int flags) { int -w32_shutdown(int fd, int how) { +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]); @@ -317,15 +321,17 @@ w32_shutdown(int fd, int how) { } int -w32_socketpair(int domain, int type, int protocol, int sv[2]) { - errno = ENOTSUP; +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) { +w32_pipe(int *pfds) +{ int read_index, write_index; struct w32_io* pio[2]; @@ -350,13 +356,15 @@ w32_pipe(int *pfds) { 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); + 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; } int -w32_open(const char *pathname, int flags, ...) { +w32_open(const char *pathname, int flags, ...) +{ int min_index = fd_table_get_min_index(); struct w32_io* pio; @@ -376,64 +384,66 @@ w32_open(const char *pathname, int flags, ...) { } int -w32_read(int fd, void *dst, size_t max) { +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) { +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); +int +w32_writev(int fd, const struct iovec *iov, int iovcnt) +{ + int written = 0; + int i = 0; - if (ret > 0) { - written += ret; - } - } + 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; + return written; } int -w32_fstat(int fd, struct w32_stat *buf) { +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) { +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) { +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]; + pio = fd_table.w32_ios[fd]; if (FILETYPE(pio) == FILE_TYPE_CHAR) return 1; else { @@ -443,7 +453,8 @@ w32_isatty(int fd) { } FILE* -w32_fdopen(int fd, const char *mode) { +w32_fdopen(int fd, const char *mode) +{ errno = 0; if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { errno = EBADF; @@ -454,13 +465,13 @@ w32_fdopen(int fd, const char *mode) { } int -w32_close(int fd) { +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; - } + if ((fd < 0) || (fd > MAX_FDS - 1) || fd_table.w32_ios[fd] == NULL) { + errno = EBADF; + return -1; + } pio = fd_table.w32_ios[fd]; @@ -480,7 +491,8 @@ w32_close(int fd) { } static int -w32_io_process_fd_flags(struct w32_io* pio, int flags) { +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); @@ -491,7 +503,7 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags) { 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", + debug("fcntl - SetHandleInformation failed %d, io:%p", GetLastError(), pio); errno = EOTHER; return -1; @@ -502,42 +514,43 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags) { } int -w32_fcntl(int fd, int cmd, ... /* arg */) { +w32_fcntl(int fd, int cmd, ... /* arg */) +{ va_list valist; va_start(valist, cmd); - int ret = 0; + int ret = 0; CHECK_FD(fd); switch (cmd) { case F_GETFL: ret = fd_table.w32_ios[fd]->fd_status_flags; - break; + break; case F_SETFL: fd_table.w32_ios[fd]->fd_status_flags = va_arg(valist, int); ret = 0; - break; + break; case F_GETFD: - ret = fd_table.w32_ios[fd]->fd_flags; - break; + 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; + 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; - } + break; + } - va_end(valist); - return ret; + 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) { +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]; @@ -566,12 +579,12 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep } /* TODO - see if this needs to be supported */ - //if (exceptfds) { - // errno = EOPNOTSUPP; - // debug("select - ERROR: exceptfds not supported"); - // DebugBreak(); - // return -1; - //} + /* if (exceptfds) { + errno = EOPNOTSUPP; + debug("select - ERROR: exceptfds not supported"); + DebugBreak(); + return -1; + } */ if (readfds) { for (i = 0; i < fds; i++) @@ -602,11 +615,10 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep * 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 ((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; @@ -618,8 +630,8 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep 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 ((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; @@ -636,7 +648,6 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep /* 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); @@ -677,7 +688,6 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep /* 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); @@ -693,9 +703,8 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep } } - if (out_ready_fds == 0) + if (out_ready_fds == 0) debug3("select - wait ended without any IO completion, looping again"); - } /* clear out fds that are not ready yet */ @@ -709,8 +718,8 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep 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 ((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*/ @@ -730,7 +739,8 @@ w32_select(int fds, w32_fd_set* readfds, w32_fd_set* writefds, w32_fd_set* excep } int -w32_dup(int oldfd) { +w32_dup(int oldfd) +{ int min_index; struct w32_io* pio; HANDLE src, target; @@ -773,7 +783,8 @@ w32_dup(int oldfd) { } int -w32_dup2(int oldfd, int newfd) { +w32_dup2(int oldfd, int newfd) +{ CHECK_FD(oldfd); errno = EOPNOTSUPP; debug("dup2 - ERROR: not implemented yet"); @@ -781,14 +792,17 @@ w32_dup2(int oldfd, int newfd) { } HANDLE -w32_fd_to_handle(int fd) { +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 +w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock) +{ int min_index = fd_table_get_min_index(); struct w32_io* pio; @@ -803,28 +817,31 @@ int w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock) { } memset(pio, 0, sizeof(struct w32_io)); - pio->type = is_sock? SOCK_FD : NONSOCK_FD; + pio->type = is_sock ? SOCK_FD : NONSOCK_FD; pio->handle = h; fd_table_set(pio, min_index); return min_index; } -int -w32_ftruncate(int fd, off_t length) { - CHECK_FD(fd); +int +w32_ftruncate(int fd, off_t length) +{ + LARGE_INTEGER new_postion; + 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; + new_postion.QuadPart = length; + if (!SetFilePointerEx(w32_fd_to_handle(fd), new_postion, 0, FILE_BEGIN)) + return -1; + if (!SetEndOfFile(w32_fd_to_handle(fd))) + return -1; - return 0; + return 0; } -int -w32_fsync(int fd) { - CHECK_FD(fd); - - return FlushFileBuffers(w32_fd_to_handle(fd)); +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 index ab4a02d9..1aad34a7 100644 --- a/contrib/win32/win32compat/w32fd.h +++ b/contrib/win32/win32compat/w32fd.h @@ -1,7 +1,33 @@ /* - * Author: Manoj Ampalam - * - * Definitions for Win32 wrapper functions with POSIX like signatures +* Author: Manoj Ampalam +* +* Definitions for Win32 wrapper functions with POSIX like signatures +* +* 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. */ #pragma once @@ -17,7 +43,7 @@ enum w32_io_type { }; enum w32_io_sock_state { - SOCK_INITIALIZED = 0, + 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*/ @@ -25,41 +51,35 @@ enum w32_io_sock_state { }; /* -* This structure encapsulates the state info needed to map a File Descriptor +* 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; + char *buf; /*internal read buffer*/ 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; + DWORD remaining; /*bytes in internal buffer remaining to be read by application*/ + DWORD completed; /*bytes in internal buffer already read by application*/ 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; + char *buf; /*internal write buffer*/ 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; + DWORD remaining; /*bytes in internal buffer remaining to be written to network*/ + DWORD completed; /*bytes in internal buffer already written to network*/ 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; + 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; @@ -89,10 +109,8 @@ 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_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); @@ -145,16 +163,16 @@ int termio_close(struct w32_io* pio); /* 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 +/* open modes */ #ifndef S_IRUSR -#define S_IRUSR 00400 //user has read permission -#endif // ! S_IRUSR +#define S_IRUSR 00400 /* user has read permission */ +#endif /* ! S_IRUSR */ #ifndef S_IWUSR -#define S_IWUSR 00200 //user has write permission +#define S_IWUSR 00200 /* user has write permission */ #endif #ifndef S_IRGRP -#define S_IRGRP 00040 //group has read permission +#define S_IRGRP 00040 /* group has read permission */ #endif #ifndef S_IROTH -#define S_IROTH 00004 //others have read permission +#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 index d23e2ef6..1df65d5b 100644 --- a/contrib/win32/win32compat/w32log.c +++ b/contrib/win32/win32compat/w32log.c @@ -27,11 +27,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include #include #include #include + #include "inc\syslog.h" #include "misc_internal.h" @@ -39,14 +39,15 @@ static int logfd = -1; void -openlog(char *ident, unsigned int option, int facility) { +openlog(char *ident, unsigned int option, int facility) +{ if (logfd != -1 || ident == NULL) return; - + wchar_t path[PATH_MAX], log_file[PATH_MAX + 12]; if (GetModuleFileNameW(NULL, path, PATH_MAX) == 0) - return; + path[PATH_MAX - 1] = '\0'; /* split path root and module */ @@ -64,20 +65,20 @@ openlog(char *ident, unsigned int option, int facility) { memcpy(p, L"log\0", 8); } - logfd = _wopen(log_file, O_WRONLY | O_CREAT | O_APPEND, - S_IREAD | S_IWRITE); + 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); + SetHandleInformation((HANDLE)_get_osfhandle(logfd), HANDLE_FLAG_INHERIT, 0); } void -closelog(void) { +closelog(void) +{ /*NOOP*/ } -void -syslog(int priority, const char *format, const char *formatBuffer) { +void +syslog(int priority, const char *format, const char *formatBuffer) +{ char msgbufTimestamp[MSGBUFSIZ]; SYSTEMTIME st; diff --git a/contrib/win32/win32compat/win32_dirent.c b/contrib/win32/win32compat/win32_dirent.c index dcfe77a2..28891ac8 100644 --- a/contrib/win32/win32compat/win32_dirent.c +++ b/contrib/win32/win32compat/win32_dirent.c @@ -1,19 +1,43 @@ -// win32_dirent.c -// directory entry functions in Windows platform like Ubix/Linux -// opendir(), readdir(), closedir(). +/* +* Copyright (c) 2016 Microsoft Corp. +* All rights reserved +* +* directory entry functions in Windows platform like Ubix/Linux +* opendir(), readdir(), closedir(). +* +* 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 "inc\utf.h" +#include "inc\utf.h" #include "inc\dirent.h" #include "inc\libgen.h" #include "misc_internal.h" - struct DIR_ { intptr_t hFile; struct _wfinddata_t c_file; @@ -22,7 +46,8 @@ struct DIR_ { /* 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) +DIR * +opendir(const char *name) { struct _wfinddata_t c_file; intptr_t hFile; @@ -30,17 +55,17 @@ DIR * opendir(const char *name) wchar_t searchstr[PATH_MAX]; wchar_t* wname = NULL; int needed; - + if ((wname = utf8_to_utf16(sanitized_path(name))) == NULL) { errno = ENOMEM; return NULL; } - // add *.* for Windows _findfirst() search pattern + /* add *.* for Windows _findfirst() search pattern */ swprintf_s(searchstr, PATH_MAX, L"%s\\*.*", wname); free(wname); - if ((hFile = _wfindfirst(searchstr, &c_file)) == -1L) + if ((hFile = _wfindfirst(searchstr, &c_file)) == -1L) return NULL; /* errno is set by _wfindfirst */ else { if ((pdir = malloc(sizeof(DIR))) == NULL) { @@ -48,34 +73,36 @@ DIR * opendir(const char *name) 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 ; + return pdir; } } /* Close the directory stream DIRP. Return 0 if successful, -1 if not. */ -int closedir(DIR *dirp) +int +closedir(DIR *dirp) { - if ( dirp && (dirp->hFile) ) { - _findclose( dirp->hFile ); - dirp->hFile = 0; - free (dirp); - } + if (dirp && (dirp->hFile)) { + _findclose(dirp->hFile); + dirp->hFile = 0; + free(dirp); + } - return 0; + 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 * +readdir(void *avp) { static struct dirent pdirentry; struct _wfinddata_t c_file; @@ -86,11 +113,10 @@ struct dirent *readdir(void *avp) if (dirp->first) { memcpy(&c_file, &dirp->c_file, sizeof(c_file)); dirp->first = 0; - } - else if (_wfindnext(dirp->hFile, &c_file) != 0) + } else if (_wfindnext(dirp->hFile, &c_file) != 0) return NULL; - - if (wcscmp(c_file.name, L".") == 0 || wcscmp(c_file.name, L"..") == 0 ) + + if (wcscmp(c_file.name, L".") == 0 || wcscmp(c_file.name, L"..") == 0) continue; if ((tmp = utf16_to_utf8(c_file.name)) == NULL) { @@ -101,13 +127,14 @@ struct dirent *readdir(void *avp) 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 ; - } + 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) +/* return last part of a path. The last path being a filename */ +char * +basename(char *path) { char *pdest; @@ -115,10 +142,10 @@ char *basename(char *path) return "."; pdest = strrchr(path, '/'); if (pdest) - return (pdest+1); + return (pdest + 1); pdest = strrchr(path, '\\'); if (pdest) - return (pdest+1); - - return path; // path does not have a slash + return (pdest + 1); + + return path; /* path does not have a slash */ } diff --git a/contrib/win32/win32compat/win32_zlib.c b/contrib/win32/win32compat/win32_zlib.c index 0302ff81..8d407334 100644 --- a/contrib/win32/win32compat/win32_zlib.c +++ b/contrib/win32/win32compat/win32_zlib.c @@ -32,33 +32,38 @@ #include "inc\zlib.h" - int -deflateEnd(z_streamp strm) { +deflateEnd(z_streamp strm) +{ return Z_DATA_ERROR; } int -inflateEnd(z_streamp strm) { +inflateEnd(z_streamp strm) +{ return Z_DATA_ERROR; } int -deflateInit(z_streamp strm, int level) { +deflateInit(z_streamp strm, int level) +{ return Z_DATA_ERROR; } int -inflateInit(z_streamp strm) { +inflateInit(z_streamp strm) +{ return Z_DATA_ERROR; } int -deflate(z_streamp strm, int flush) { +deflate(z_streamp strm, int flush) +{ return Z_DATA_ERROR; } int -inflate(z_streamp strm, int flush) { +inflate(z_streamp strm, int flush) +{ return Z_DATA_ERROR; } diff --git a/groupaccess.c b/groupaccess.c index 2518c848..bea3d6dd 100644 --- a/groupaccess.c +++ b/groupaccess.c @@ -33,6 +33,9 @@ #include #include #include +#ifdef WINDOWS +#include +#endif #include "xmalloc.h" #include "groupaccess.h" @@ -49,6 +52,82 @@ static char **groups_byname; int ga_init(const char *user, gid_t base) { +#ifdef WINDOWS + DWORD i = 0, j = 0; + LPLOCALGROUP_USERS_INFO_0 local_groups_info = NULL, tmp_groups_info; + wchar_t *user_utf16 = NULL, *full_name_utf16 = NULL, *udom_utf16 = NULL, *tmp; + char *group_utf8 = NULL; + DWORD entries_read = 0, total_entries = 0, full_name_len = 0, index = 0; + NET_API_STATUS nStatus; + + if (ngroups > 0) + ga_free(); + + user_utf16 = utf8_to_utf16(user); + if ((user_utf16 = utf8_to_utf16(user)) == NULL) { + errno = ENOMEM; + goto done; + } + full_name_len = wcslen(user_utf16) + 1; + if ((full_name_utf16 = malloc(full_name_len * sizeof(wchar_t))) == NULL) { + errno = ENOMEM; + goto done; + } + + if ((tmp = wcschr(user_utf16, L'@')) != NULL) { + udom_utf16 = tmp + 1; + *tmp = L'\0'; + index = wcslen(udom_utf16) + 1; + wmemcpy(full_name_utf16, udom_utf16, index); + full_name_utf16[wcslen(udom_utf16)] = L'\\'; + } + wmemcpy(full_name_utf16 + index, user_utf16, wcslen(user_utf16) + 1); + + nStatus = NetUserGetLocalGroups(NULL, + full_name_utf16, + 0, + LG_INCLUDE_INDIRECT, + (LPBYTE *)&local_groups_info, + MAX_PREFERRED_LENGTH, + &entries_read, + &total_entries); + + if (NERR_Success != nStatus) { + error("NetUserGetLocalGroups() failed with error: %u", + nStatus); + errno = ENOENT; + goto done; + } + + if (entries_read != total_entries) { + error("NetUserGetLocalGroups(): entries_read (%u) is not equal to " + "total_entries (%u) for user %.100s", entries_read, total_entries, user); + errno = ENOENT; + goto done; + } + + if ((tmp_groups_info = local_groups_info) != NULL) { + groups_byname = xcalloc(entries_read, sizeof(*groups_byname)); + for (i = 0, j = 0; i < total_entries; i++) + { + if ((group_utf8 = utf16_to_utf8(tmp_groups_info->lgrui0_name)) == NULL) { + errno = ENOMEM; + goto done; + } + groups_byname[j++] = group_utf8; + tmp_groups_info++; + } + } + +done: + if(user_utf16 != NULL) + free(user_utf16); + if(full_name_utf16 != NULL) + free(full_name_utf16); + if (local_groups_info != NULL) + NetApiBufferFree(local_groups_info); + +#else /* !WINDOWS */ gid_t *groups_bygid; int i, j; struct group *gr; @@ -70,7 +149,9 @@ ga_init(const char *user, gid_t base) if ((gr = getgrgid(groups_bygid[i])) != NULL) groups_byname[j++] = xstrdup(gr->gr_name); free(groups_bygid); +#endif /* !WINDOWS */ return (ngroups = j); + } /* diff --git a/kex.c b/kex.c index 6a94bc53..a30dabe5 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.127 2016/10/10 19:28:48 markus Exp $ */ +/* $OpenBSD: kex.c,v 1.128 2017/02/03 23:01:19 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -211,7 +211,8 @@ kex_names_cat(const char *a, const char *b) /* * Assemble a list of algorithms from a default list and a string from a * configuration file. The user-provided string may begin with '+' to - * indicate that it should be appended to the default. + * indicate that it should be appended to the default or '-' that the + * specified names should be removed. */ int kex_assemble_names(const char *def, char **list) @@ -222,14 +223,18 @@ kex_assemble_names(const char *def, char **list) *list = strdup(def); return 0; } - if (**list != '+') { - return 0; + if (**list == '+') { + if ((ret = kex_names_cat(def, *list + 1)) == NULL) + return SSH_ERR_ALLOC_FAIL; + free(*list); + *list = ret; + } else if (**list == '-') { + if ((ret = match_filter_list(def, *list + 1)) == NULL) + return SSH_ERR_ALLOC_FAIL; + free(*list); + *list = ret; } - if ((ret = kex_names_cat(def, *list + 1)) == NULL) - return SSH_ERR_ALLOC_FAIL; - free(*list); - *list = ret; return 0; } diff --git a/match.c b/match.c index c15dcd1e..aeba4bb7 100644 --- a/match.c +++ b/match.c @@ -1,4 +1,4 @@ -/* $OpenBSD: match.c,v 1.33 2016/11/06 05:46:37 djm Exp $ */ +/* $OpenBSD: match.c,v 1.34 2017/02/03 23:01:19 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -284,3 +284,32 @@ match_list(const char *client, const char *server, u_int *next) free(s); return NULL; } + +/* + * Filters a comma-separated list of strings, excluding any entry matching + * the 'filter' pattern list. Caller must free returned string. + */ +char * +match_filter_list(const char *proposal, const char *filter) +{ + size_t len = strlen(proposal) + 1; + char *fix_prop = malloc(len); + char *orig_prop = strdup(proposal); + char *cp, *tmp; + + if (fix_prop == NULL || orig_prop == NULL) + return NULL; + + tmp = orig_prop; + *fix_prop = '\0'; + while ((cp = strsep(&tmp, ",")) != NULL) { + if (match_pattern_list(cp, filter, 0) != 1) { + if (*fix_prop != '\0') + strlcat(fix_prop, ",", len); + strlcat(fix_prop, cp, len); + } + } + free(orig_prop); + return fix_prop; +} + diff --git a/match.h b/match.h index db97ca8f..937ba041 100644 --- a/match.h +++ b/match.h @@ -1,4 +1,4 @@ -/* $OpenBSD: match.h,v 1.16 2015/05/04 06:10:48 djm Exp $ */ +/* $OpenBSD: match.h,v 1.17 2017/02/03 23:01:19 djm Exp $ */ /* * Author: Tatu Ylonen @@ -20,6 +20,7 @@ int match_hostname(const char *, const char *); int match_host_and_ip(const char *, const char *, const char *); int match_user(const char *, const char *, const char *, const char *); char *match_list(const char *, const char *, u_int *); +char *match_filter_list(const char *, const char *); /* addrmatch.c */ int addr_match_list(const char *, const char *); diff --git a/misc.c b/misc.c index 3dfcef6f..8a644051 100644 --- a/misc.c +++ b/misc.c @@ -225,6 +225,10 @@ pwcopy(struct passwd *pw) #endif copy->pw_dir = xstrdup(pw->pw_dir); copy->pw_shell = xstrdup(pw->pw_shell); +#ifdef WINDOWS + copy->pw_sid = xstrdup(pw->pw_sid); +#endif /* WINDOWS */ + return copy; } @@ -439,7 +443,7 @@ colon(char *cp) #ifdef WINDOWS /* * Account for Windows file names in the form x: or /x: - * Note: This may conflict with potential single charecter targets + * Note: This may conflict with potential single character targets */ if ((*cp != '\0' && cp[1] == ':') || (cp[0] == '/' && cp[1] != '\0' && cp[2] == ':')) diff --git a/monitor.c b/monitor.c index 43f48470..96d22b7e 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.166 2016/09/28 16:33:06 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.167 2017/02/03 23:05:57 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -283,6 +283,7 @@ monitor_permit_authentications(int permit) void monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) { + struct ssh *ssh = active_state; /* XXX */ struct mon_table *ent; int authenticated = 0, partial = 0; @@ -356,6 +357,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) debug("%s: %s has been authenticated by privileged process", __func__, authctxt->user); + ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); mm_get_keystate(pmonitor); @@ -695,6 +697,7 @@ mm_answer_sign(int sock, Buffer *m) int mm_answer_pwnamallow(int sock, Buffer *m) { + struct ssh *ssh = active_state; /* XXX */ char *username; struct passwd *pwent; int allowed = 0; @@ -739,6 +742,8 @@ mm_answer_pwnamallow(int sock, Buffer *m) buffer_put_cstring(m, pwent->pw_shell); out: + ssh_packet_set_log_preamble(ssh, "%suser %s", + authctxt->valid ? "authenticating" : "invalid ", authctxt->user); buffer_put_string(m, &options, sizeof(options)); #define M_CP_STROPT(x) do { \ diff --git a/mux.c b/mux.c index 265c5f12..2d6639c5 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.63 2016/10/19 23:21:56 dtucker Exp $ */ +/* $OpenBSD: mux.c,v 1.64 2017/01/21 11:32:04 guenther Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -2161,7 +2161,6 @@ int muxclient(const char *path) { struct sockaddr_un addr; - socklen_t sun_len; int sock; u_int pid; @@ -2185,8 +2184,6 @@ muxclient(const char *path) memset(&addr, '\0', sizeof(addr)); addr.sun_family = AF_UNIX; - sun_len = offsetof(struct sockaddr_un, sun_path) + - strlen(path) + 1; if (strlcpy(addr.sun_path, path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) @@ -2196,7 +2193,7 @@ muxclient(const char *path) if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) fatal("%s socket(): %s", __func__, strerror(errno)); - if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { switch (muxclient_command) { case SSHMUX_COMMAND_OPEN: case SSHMUX_COMMAND_STDIO_FWD: diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c index 128f9b6e..47237dea 100644 --- a/openbsd-compat/arc4random.c +++ b/openbsd-compat/arc4random.c @@ -83,10 +83,11 @@ _rs_init(u_char *buf, size_t n) static 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(); + if (CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) == FALSE || + CryptGenRandom(hProvider, len, s) == FALSE || + CryptReleaseContext(hProvider, 0) == FALSE) + fatal("%s Crypto error: %d", __func__, GetLastError()); } #else /* !WINDOWS */ diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index c03ac686..6285ff4c 100644 --- a/openbsd-compat/bsd-misc.c +++ b/openbsd-compat/bsd-misc.c @@ -211,7 +211,11 @@ tcsendbreak(int fd, int duration) } #endif /* HAVE_TCSENDBREAK */ -#ifdef HAVE_SIGACTION /* Moved out of function definition */ +/* + * This is not a BSD routine. Why is this here? + * Macro added to override this implementation for Windows + */ +#ifndef HAVE_MYSIGNAL mysig_t mysignal(int sig, mysig_t act) { diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index 77029fa6..6f08b09f 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -95,12 +95,10 @@ int unsetenv(const char *); #endif /* wrapper for signal interface */ -#ifdef HAVE_SIGACTION typedef void (*mysig_t)(int); mysig_t mysignal(int sig, mysig_t act); #define signal(a,b) mysignal(a,b) -#endif #ifndef HAVE_ISBLANK int isblank(int); diff --git a/packet.c b/packet.c index ad1f6b49..94e8460c 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.243 2016/10/11 21:47:45 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.245 2017/02/03 23:03:33 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -352,6 +352,25 @@ ssh_packet_get_mux(struct ssh *ssh) return ssh->state->mux; } +int +ssh_packet_set_log_preamble(struct ssh *ssh, const char *fmt, ...) +{ + va_list args; + int r; + + free(ssh->log_preamble); + if (fmt == NULL) + ssh->log_preamble = NULL; + else { + va_start(args, fmt); + r = vasprintf(&ssh->log_preamble, fmt, args); + va_end(args); + if (r < 0 || ssh->log_preamble == NULL) + return SSH_ERR_ALLOC_FAIL; + } + return 0; +} + int ssh_packet_stop_discard(struct ssh *ssh) { @@ -1049,7 +1068,7 @@ ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len) /* Time-based rekeying */ if (state->rekey_interval != 0 && - state->rekey_time + state->rekey_interval <= monotime()) + (int64_t)state->rekey_time + state->rekey_interval <= monotime()) return 1; /* Always rekey when MAX_PACKETS sent in either direction */ @@ -2074,27 +2093,36 @@ ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...) fatal("%s: %s", __func__, ssh_err(r)); } +static void +fmt_connection_id(struct ssh *ssh, char *s, size_t l) +{ + snprintf(s, l, "%.200s%s%s port %d", + ssh->log_preamble ? ssh->log_preamble : "", + ssh->log_preamble ? " " : "", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); +} + /* * Pretty-print connection-terminating errors and exit. */ void sshpkt_fatal(struct ssh *ssh, const char *tag, int r) { + char remote_id[512]; + + fmt_connection_id(ssh, remote_id, sizeof(remote_id)); + switch (r) { case SSH_ERR_CONN_CLOSED: - logdie("Connection closed by %.200s port %d", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + logdie("Connection closed by %s", remote_id); case SSH_ERR_CONN_TIMEOUT: - logdie("Connection %s %.200s port %d timed out", - ssh->state->server_side ? "from" : "to", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + logdie("Connection %s %s timed out", + ssh->state->server_side ? "from" : "to", remote_id); case SSH_ERR_DISCONNECTED: - logdie("Disconnected from %.200s port %d", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + logdie("Disconnected from %s", remote_id); case SSH_ERR_SYSTEM_ERROR: if (errno == ECONNRESET) - logdie("Connection reset by %.200s port %d", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + logdie("Connection reset by %s", remote_id); /* FALLTHROUGH */ case SSH_ERR_NO_CIPHER_ALG_MATCH: case SSH_ERR_NO_MAC_ALG_MATCH: @@ -2102,17 +2130,16 @@ sshpkt_fatal(struct ssh *ssh, const char *tag, int r) case SSH_ERR_NO_KEX_ALG_MATCH: case SSH_ERR_NO_HOSTKEY_ALG_MATCH: if (ssh && ssh->kex && ssh->kex->failed_choice) { - logdie("Unable to negotiate with %.200s port %d: %s. " - "Their offer: %s", ssh_remote_ipaddr(ssh), - ssh_remote_port(ssh), ssh_err(r), + logdie("Unable to negotiate with %s: %s. " + "Their offer: %s", remote_id, ssh_err(r), ssh->kex->failed_choice); } /* FALLTHROUGH */ default: - logdie("%s%sConnection %s %.200s port %d: %s", + logdie("%s%sConnection %s %s: %s", tag != NULL ? tag : "", tag != NULL ? ": " : "", ssh->state->server_side ? "from" : "to", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ssh_err(r)); + remote_id, ssh_err(r)); } } @@ -2125,7 +2152,7 @@ sshpkt_fatal(struct ssh *ssh, const char *tag, int r) void ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...) { - char buf[1024]; + char buf[1024], remote_id[512]; va_list args; static int disconnecting = 0; int r; @@ -2138,12 +2165,13 @@ ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...) * Format the message. Note that the caller must make sure the * message is of limited size. */ + fmt_connection_id(ssh, remote_id, sizeof(remote_id)); va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); /* Display the error locally */ - logit("Disconnecting: %.100s", buf); + logit("Disconnecting %s: %.100s", remote_id, buf); /* * Send the disconnect message to the other side, and wait @@ -2396,10 +2424,10 @@ ssh_packet_send_ignore(struct ssh *ssh, int nbytes) } void -ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, time_t seconds) +ssh_packet_set_rekey_limits(struct ssh *ssh, u_int64_t bytes, u_int32_t seconds) { - debug3("rekey after %llu bytes, %d seconds", (unsigned long long)bytes, - (int)seconds); + debug3("rekey after %llu bytes, %u seconds", (unsigned long long)bytes, + (unsigned int)seconds); ssh->state->rekey_limit = bytes; ssh->state->rekey_interval = seconds; } diff --git a/packet.h b/packet.h index bfe7da61..0d25b352 100644 --- a/packet.h +++ b/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.74 2016/10/11 21:47:45 djm Exp $ */ +/* $OpenBSD: packet.h,v 1.76 2017/02/03 23:03:33 djm Exp $ */ /* * Author: Tatu Ylonen @@ -62,6 +62,9 @@ struct ssh { char *local_ipaddr; int local_port; + /* Optional preamble for log messages (e.g. username) */ + char *log_preamble; + /* Dispatcher table */ dispatch_fn *dispatch[DISPATCH_MAX]; /* number of packets to ignore in the dispatcher */ @@ -104,6 +107,8 @@ void ssh_packet_set_server(struct ssh *); void ssh_packet_set_authenticated(struct ssh *); void ssh_packet_set_mux(struct ssh *); int ssh_packet_get_mux(struct ssh *); +int ssh_packet_set_log_preamble(struct ssh *, const char *, ...) + __attribute__((format(printf, 2, 3))); int ssh_packet_log_type(u_char); @@ -154,7 +159,7 @@ int ssh_remote_port(struct ssh *); const char *ssh_local_ipaddr(struct ssh *); int ssh_local_port(struct ssh *); -void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, time_t); +void ssh_packet_set_rekey_limits(struct ssh *, u_int64_t, u_int32_t); time_t ssh_packet_get_rekey_timeout(struct ssh *); void *ssh_packet_get_input(struct ssh *); diff --git a/readconf.c b/readconf.c index bf52589f..bfcd2b3f 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.262 2016/10/25 04:08:13 jsg Exp $ */ +/* $OpenBSD: readconf.c,v 1.268 2017/02/03 23:01:19 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -93,7 +93,7 @@ Host books.com RemoteForward 9999 shadows.cs.hut.fi:9999 - Cipher 3des + Ciphers 3des-cbc Host fascist.blob.com Port 23123 @@ -108,7 +108,7 @@ PublicKeyAuthentication no Host *.su - Cipher none + Ciphers aes128-ctr PasswordAuthentication no Host vpn.fake.com @@ -180,6 +180,44 @@ static struct { const char *name; OpCodes opcode; } keywords[] = { + /* Deprecated options */ + { "fallbacktorsh", oDeprecated }, + { "globalknownhostsfile2", oDeprecated }, + { "rhostsauthentication", oDeprecated }, + { "userknownhostsfile2", oDeprecated }, + { "useroaming", oDeprecated }, + { "usersh", oDeprecated }, + + /* Unsupported options */ + { "afstokenpassing", oUnsupported }, + { "kerberosauthentication", oUnsupported }, + { "kerberostgtpassing", oUnsupported }, + + /* Sometimes-unsupported options */ +#if defined(GSSAPI) + { "gssapiauthentication", oGssAuthentication }, + { "gssapidelegatecredentials", oGssDelegateCreds }, +# else + { "gssapiauthentication", oUnsupported }, + { "gssapidelegatecredentials", oUnsupported }, +#endif +#ifdef ENABLE_PKCS11 + { "smartcarddevice", oPKCS11Provider }, + { "pkcs11provider", oPKCS11Provider }, +# else + { "smartcarddevice", oUnsupported }, + { "pkcs11provider", oUnsupported }, +#endif +#ifdef WITH_SSH1 + { "rsaauthentication", oRSAAuthentication }, + { "rhostsrsaauthentication", oRhostsRSAAuthentication }, + { "compressionlevel", oCompressionLevel }, +# else + { "rsaauthentication", oUnsupported }, + { "rhostsrsaauthentication", oUnsupported }, + { "compressionlevel", oUnsupported }, +#endif + { "forwardagent", oForwardAgent }, { "forwardx11", oForwardX11 }, { "forwardx11trusted", oForwardX11Trusted }, @@ -188,30 +226,15 @@ static struct { { "xauthlocation", oXAuthLocation }, { "gatewayports", oGatewayPorts }, { "useprivilegedport", oUsePrivilegedPort }, - { "rhostsauthentication", oDeprecated }, { "passwordauthentication", oPasswordAuthentication }, { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, { "kbdinteractivedevices", oKbdInteractiveDevices }, - { "rsaauthentication", oRSAAuthentication }, { "pubkeyauthentication", oPubkeyAuthentication }, { "dsaauthentication", oPubkeyAuthentication }, /* alias */ - { "rhostsrsaauthentication", oRhostsRSAAuthentication }, { "hostbasedauthentication", oHostbasedAuthentication }, { "challengeresponseauthentication", oChallengeResponseAuthentication }, { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ - { "kerberosauthentication", oUnsupported }, - { "kerberostgtpassing", oUnsupported }, - { "afstokenpassing", oUnsupported }, -#if defined(GSSAPI) - { "gssapiauthentication", oGssAuthentication }, - { "gssapidelegatecredentials", oGssDelegateCreds }, -#else - { "gssapiauthentication", oUnsupported }, - { "gssapidelegatecredentials", oUnsupported }, -#endif - { "fallbacktorsh", oDeprecated }, - { "usersh", oDeprecated }, { "identityfile", oIdentityFile }, { "identityfile2", oIdentityFile }, /* obsolete */ { "identitiesonly", oIdentitiesOnly }, @@ -233,15 +256,12 @@ static struct { { "match", oMatch }, { "escapechar", oEscapeChar }, { "globalknownhostsfile", oGlobalKnownHostsFile }, - { "globalknownhostsfile2", oDeprecated }, { "userknownhostsfile", oUserKnownHostsFile }, - { "userknownhostsfile2", oDeprecated }, { "connectionattempts", oConnectionAttempts }, { "batchmode", oBatchMode }, { "checkhostip", oCheckHostIP }, { "stricthostkeychecking", oStrictHostKeyChecking }, { "compression", oCompression }, - { "compressionlevel", oCompressionLevel }, { "tcpkeepalive", oTCPKeepAlive }, { "keepalive", oTCPKeepAlive }, /* obsolete */ { "numberofpasswordprompts", oNumberOfPasswordPrompts }, @@ -250,13 +270,6 @@ static struct { { "preferredauthentications", oPreferredAuthentications }, { "hostkeyalgorithms", oHostKeyAlgorithms }, { "bindaddress", oBindAddress }, -#ifdef ENABLE_PKCS11 - { "smartcarddevice", oPKCS11Provider }, - { "pkcs11provider", oPKCS11Provider }, -#else - { "smartcarddevice", oUnsupported }, - { "pkcs11provider", oUnsupported }, -#endif { "clearallforwardings", oClearAllForwardings }, { "enablesshkeysign", oEnableSSHKeysign }, { "verifyhostkeydns", oVerifyHostKeyDNS }, @@ -277,7 +290,6 @@ static struct { { "localcommand", oLocalCommand }, { "permitlocalcommand", oPermitLocalCommand }, { "visualhostkey", oVisualHostKey }, - { "useroaming", oDeprecated }, { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, @@ -835,11 +847,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, activep = &cmdline; } - /* Strip trailing whitespace */ + /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ if ((len = strlen(line)) == 0) return 0; for (len--; len > 0; len--) { - if (strchr(WHITESPACE, line[len]) == NULL) + if (strchr(WHITESPACE "\f", line[len]) == NULL) break; line[len] = '\0'; } @@ -1187,7 +1199,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!ciphers_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg)) fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : ""); if (*activep && options->ciphers == NULL) @@ -1198,7 +1210,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!mac_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg)) fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", filename, linenum, arg ? arg : ""); if (*activep && options->macs == NULL) @@ -1210,7 +1222,8 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && + !kex_names_valid(*arg == '+' ? arg + 1 : arg)) fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : ""); if (*activep && options->kex_algorithms == NULL) @@ -1224,7 +1237,8 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) + if (*arg != '-' && + !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) fatal("%s line %d: Bad key types '%s'.", filename, linenum, arg ? arg : ""); if (*activep && *charptr == NULL) @@ -1507,6 +1521,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, flags | SSHCONF_CHECKPERM | (oactive ? 0 : SSHCONF_NEVERMATCH), activep, depth + 1); + if (r != 1 && errno != ENOENT) { + fatal("Can't open user config file " + "%.100s: %.100s", gl.gl_pathv[i], + strerror(errno)); + } /* * don't let Match in includes clobber the * containing file's Match state. @@ -2453,10 +2472,10 @@ dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds) /* oDynamicForward */ for (i = 0; i < count; i++) { fwd = &fwds[i]; - if (code == oDynamicForward && + if (code == oDynamicForward && fwd->connect_host != NULL && strcmp(fwd->connect_host, "socks") != 0) continue; - if (code == oLocalForward && + if (code == oLocalForward && fwd->connect_host != NULL && strcmp(fwd->connect_host, "socks") == 0) continue; printf("%s", lookup_opcode_name(code)); @@ -2529,8 +2548,10 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); dump_cfg_fmtint(oRequestTTY, o->request_tty); +#ifdef WITH_RSA1 dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication); dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication); +#endif dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); @@ -2542,7 +2563,9 @@ dump_client_config(Options *o, const char *host) /* Integer options */ dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); +#ifdef WITH_SSH1 dump_cfg_int(oCompressionLevel, o->compression_level); +#endif dump_cfg_int(oConnectionAttempts, o->connection_attempts); dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout); dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); @@ -2562,7 +2585,9 @@ dump_client_config(Options *o, const char *host) dump_cfg_string(oLocalCommand, o->local_command); dump_cfg_string(oLogLevel, log_level_name(o->log_level)); dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); +#ifdef ENABLE_PKCS11 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); +#endif dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); diff --git a/regress/agent-getpeereid.sh b/regress/agent-getpeereid.sh index 91621a59..34bced15 100644 --- a/regress/agent-getpeereid.sh +++ b/regress/agent-getpeereid.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent-getpeereid.sh,v 1.7 2016/09/26 21:34:38 bluhm Exp $ +# $OpenBSD: agent-getpeereid.sh,v 1.8 2017/01/06 02:51:16 djm Exp $ # Placed in the Public Domain. tid="disallow agent attach from other uid" @@ -32,17 +32,17 @@ if [ $r -ne 0 ]; then else chmod 644 ${SSH_AUTH_SOCK} - ssh-add -l > /dev/null 2>&1 + ${SSHADD} -l > /dev/null 2>&1 r=$? if [ $r -ne 1 ]; then fail "ssh-add failed with $r != 1" fi if test -z "$sudo" ; then # doas - ${SUDO} -n -u ${UNPRIV} ssh-add -l 2>/dev/null + ${SUDO} -n -u ${UNPRIV} ${SSHADD} -l 2>/dev/null else # sudo - < /dev/null ${SUDO} -S -u ${UNPRIV} ssh-add -l 2>/dev/null + < /dev/null ${SUDO} -S -u ${UNPRIV} ${SSHADD} -l 2>/dev/null fi r=$? if [ $r -lt 2 ]; then diff --git a/regress/forwarding.sh b/regress/forwarding.sh index 2539db9b..60c37d89 100644 --- a/regress/forwarding.sh +++ b/regress/forwarding.sh @@ -1,4 +1,4 @@ -# $OpenBSD: forwarding.sh,v 1.16 2016/04/14 23:57:17 djm Exp $ +# $OpenBSD: forwarding.sh,v 1.19 2017/01/30 05:22:14 djm Exp $ # Placed in the Public Domain. tid="local and remote forwarding" @@ -11,7 +11,6 @@ base=33 last=$PORT fwd="" CTL=$OBJ/ctl-sock -rm -f $CTL for j in 0 1 2; do for i in 0 1 2; do @@ -29,7 +28,8 @@ for p in ${SSH_PROTOCOLS}; do q=$p fi trace "start forwarding, fork to background" - ${SSH} -$p -F $OBJ/ssh_config -f $fwd somehost sleep 10 + rm -f $CTL + ${SSH} -S $CTL -M -$p -F $OBJ/ssh_config -f $fwd somehost sleep 10 trace "transfer over forwarded channels and check result" ${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \ @@ -37,7 +37,7 @@ for p in ${SSH_PROTOCOLS}; do test -s ${COPY} || fail "failed copy of ${DATA}" cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}" - sleep 10 + ${SSH} -F $OBJ/ssh_config -S $CTL -O exit somehost done for p in ${SSH_PROTOCOLS}; do @@ -52,7 +52,7 @@ for d in L R; do -$d ${base}04:127.0.0.1:$PORT \ -oExitOnForwardFailure=yes somehost true if [ $? != 0 ]; then - fail "connection failed, should not" + fatal "connection failed, should not" else # this one should fail ${SSH} -q -$p -F $OBJ/ssh_config \ @@ -75,30 +75,32 @@ for p in ${SSH_PROTOCOLS}; do ${SSH} -$p -F $OBJ/ssh_config -oClearAllForwardings=yes somehost true trace "clear local forward proto $p" - ${SSH} -$p -f -F $OBJ/ssh_config -L ${base}01:127.0.0.1:$PORT \ + rm -f $CTL + ${SSH} -S $CTL -M -$p -f -F $OBJ/ssh_config -L ${base}01:127.0.0.1:$PORT \ -oClearAllForwardings=yes somehost sleep 10 if [ $? != 0 ]; then fail "connection failed with cleared local forwarding" else # this one should fail - ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 true \ + ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 somehost true \ >>$TEST_REGRESS_LOGFILE 2>&1 && \ fail "local forwarding not cleared" fi - sleep 10 + ${SSH} -F $OBJ/ssh_config -S $CTL -O exit somehost trace "clear remote forward proto $p" - ${SSH} -$p -f -F $OBJ/ssh_config -R ${base}01:127.0.0.1:$PORT \ + rm -f $CTL + ${SSH} -S $CTL -M -$p -f -F $OBJ/ssh_config -R ${base}01:127.0.0.1:$PORT \ -oClearAllForwardings=yes somehost sleep 10 if [ $? != 0 ]; then fail "connection failed with cleared remote forwarding" else # this one should fail - ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 true \ + ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 somehost true \ >>$TEST_REGRESS_LOGFILE 2>&1 && \ fail "remote forwarding not cleared" fi - sleep 10 + ${SSH} -F $OBJ/ssh_config -S $CTL -O exit somehost done for p in 2; do @@ -115,6 +117,7 @@ echo "LocalForward ${base}01 127.0.0.1:$PORT" >> $OBJ/ssh_config echo "RemoteForward ${base}02 127.0.0.1:${base}01" >> $OBJ/ssh_config for p in ${SSH_PROTOCOLS}; do trace "config file: start forwarding, fork to background" + rm -f $CTL ${SSH} -S $CTL -M -$p -F $OBJ/ssh_config -f somehost sleep 10 trace "config file: transfer over forwarded channels and check result" @@ -123,21 +126,24 @@ for p in ${SSH_PROTOCOLS}; do test -s ${COPY} || fail "failed copy of ${DATA}" cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}" - ${SSH} -S $CTL -O exit somehost + ${SSH} -F $OBJ/ssh_config -S $CTL -O exit somehost done for p in 2; do trace "transfer over chained unix domain socket forwards and check result" rm -f $OBJ/unix-[123].fwd - ${SSH} -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehost sleep 10 - ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10 - ${SSH} -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10 - ${SSH} -f -F $OBJ/ssh_config -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost sleep 10 + rm -f $CTL $CTL.[123] + ${SSH} -S $CTL -M -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehost sleep 10 + ${SSH} -S $CTL.1 -M -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost sleep 10 + ${SSH} -S $CTL.2 -M -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost sleep 10 + ${SSH} -S $CTL.3 -M -f -F $OBJ/ssh_config -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost sleep 10 ${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=4' \ somehost cat ${DATA} > ${COPY} test -s ${COPY} || fail "failed copy ${DATA}" cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}" - #wait - sleep 10 + ${SSH} -F $OBJ/ssh_config -S $CTL -O exit somehost + ${SSH} -F $OBJ/ssh_config -S $CTL.1 -O exit somehost + ${SSH} -F $OBJ/ssh_config -S $CTL.2 -O exit somehost + ${SSH} -F $OBJ/ssh_config -S $CTL.3 -O exit somehost done diff --git a/regress/integrity.sh b/regress/integrity.sh index 39d310de..1df2924f 100644 --- a/regress/integrity.sh +++ b/regress/integrity.sh @@ -1,12 +1,10 @@ -# $OpenBSD: integrity.sh,v 1.19 2016/11/25 02:56:49 dtucker Exp $ +# $OpenBSD: integrity.sh,v 1.20 2017/01/06 02:26:10 dtucker Exp $ # Placed in the Public Domain. tid="integrity" cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak # start at byte 2900 (i.e. after kex) and corrupt at different offsets -# XXX the test hangs if we modify the low bytes of the packet length -# XXX and ssh tries to read... tries=10 startoffset=2900 macs=`${SSH} -Q mac` @@ -27,6 +25,7 @@ for m in $macs; do elen=0 epad=0 emac=0 + etmo=0 ecnt=0 skip=0 for off in `jot $tries $startoffset`; do diff --git a/regress/netcat.c b/regress/netcat.c index 91642df3..98a08b1e 100644 --- a/regress/netcat.c +++ b/regress/netcat.c @@ -558,9 +558,8 @@ unix_connect(char *path) if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return (-1); } -#ifndef WIN32_FIXME (void)fcntl(s, F_SETFD, FD_CLOEXEC); -#endif + memset(&sun_sa, 0, sizeof(struct sockaddr_un)); sun_sa.sun_family = AF_UNIX; @@ -670,13 +669,12 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) socklen_t optlen; int flags = 0, optval; int ret; -#ifndef WIN32_FIXME + if (timeout != -1) { flags = fcntl(s, F_GETFL, 0); if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) err(1, "set non-blocking mode"); } -#endif if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { pfd.fd = s; @@ -694,10 +692,10 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) } else err(1, "poll failed"); } -#ifndef WIN32_FIXME + if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) err(1, "restoring flags"); -#endif + return (ret); } @@ -766,13 +764,6 @@ local_listen(char *host, char *port, struct addrinfo hints) * readwrite() * Loop that polls on the network file descriptor and stdin. */ - -#ifdef WIN32_FIXME -#define POLLNVAL 0x0020 -#define POLLHUP 0x0010 -#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ -#endif - void readwrite(int net_fd) { @@ -1222,9 +1213,7 @@ map_tos(char *s, int *val) { "af41", IPTOS_DSCP_AF41 }, { "af42", IPTOS_DSCP_AF42 }, { "af43", IPTOS_DSCP_AF43 }, -#ifndef WIN32_FIXME { "critical", IPTOS_PREC_CRITIC_ECP }, -#endif { "cs0", IPTOS_DSCP_CS0 }, { "cs1", IPTOS_DSCP_CS1 }, { "cs2", IPTOS_DSCP_CS2 }, @@ -1234,13 +1223,9 @@ map_tos(char *s, int *val) { "cs6", IPTOS_DSCP_CS6 }, { "cs7", IPTOS_DSCP_CS7 }, { "ef", IPTOS_DSCP_EF }, -#ifndef WIN32_FIXME { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, -#endif { "lowdelay", IPTOS_LOWDELAY }, -#ifndef WIN32_FIXME { "netcontrol", IPTOS_PREC_NETCONTROL }, -#endif { "reliability", IPTOS_RELIABILITY }, { "throughput", IPTOS_THROUGHPUT }, { NULL, -1 }, @@ -1450,10 +1435,8 @@ getproxypass(const char *proxyuser, const char *proxyhost) snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ", proxyuser, proxyhost); -#ifndef WIN32_FIXME if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL) errx(1, "Unable to read proxy passphrase"); -#endif return (pw); } diff --git a/regress/pesterTests/PlatformAbstractLayer.psm1 b/regress/pesterTests/PlatformAbstractLayer.psm1 index 7b0683f7..48f2b38c 100644 --- a/regress/pesterTests/PlatformAbstractLayer.psm1 +++ b/regress/pesterTests/PlatformAbstractLayer.psm1 @@ -75,9 +75,11 @@ Class Machine [string] $localAdminUserName = "localadmin" [string] $localAdminPassword = "Bull_dog1" [string] $localAdminAuthorizedKeyPath + [string] $sshdConfigFile = (join-path $PSScriptRoot "sshd_config") + [string] $backupFileName = (join-path $PSScriptRoot "sshd_backup") [System.Security.SecureString] $password $preLatfpSetting - $localUserprofilePath + [string] $localUserprofilePath #Members on client role [string []] $clientPrivateKeyPaths @@ -177,6 +179,47 @@ Class Machine } } + [void] SetupSingleSignon([string] $identifyFile) { + .\ssh-add.exe $identifyFile + } + + [void] CleanupSingleSignon([string] $identifyFile) { + .\ssh-add.exe -d $identifyFile + } + + [void] AddItemInSSHDConfig([string] $key, [string] $value) { + if ( $this.Platform -eq [PlatformType]::Windows ) { + Get-Content $this.sshdConfigFile | % { + if($_.StartsWith($key)) { + "#$_" + } + else {$_} + } | Set-Content $this.sshdConfigFile + Add-Content -Path $this.sshdConfigFile -Value "`r`n$key $value" + + Restart-Service sshd + } else { + } + } + + [void] BackupSSHDConfig() { + if ( $this.Platform -eq [PlatformType]::Windows ) { + if(Test-path $this.backupFileName) { + Remove-Item -Path $this.backupFileName -Force + } + + Copy-Item $this.sshdConfigFile $this.backupFileName -Force + } + } + + [void] RestoreSSHDConfig() { + if ( $this.Platform -eq [PlatformType]::Windows ) { + Copy-Item $this.backupFileName $this.sshdConfigFile -Force + Remove-Item -Path $this.backupFileName -Force + Restart-Service sshd + } + } + [void] SetupServerRemoting([Protocol] $protocol) { if ($this.Platform -eq [PlatformType]::Windows) { @@ -240,6 +283,56 @@ Class Machine } } + [void] AddLocalUser($UserName, $password) { + $a = Get-LocalUser -Name $UserName -ErrorAction Ignore + if ($a -eq $null) + { + $pass = ConvertTo-SecureString -String $this.localAdminPassword -AsPlainText -Force + $a = New-LocalUser -Name $UserName -Password $pass -AccountNeverExpires -PasswordNeverExpires -UserMayNotChangePassword + } + } + + [void] AddLocalGroup($groupName) { + $g = Get-LocalGroup -Name $groupName -ErrorAction Ignore + if ($g -eq $null) + { + $g = New-LocalGroup -Name $groupName + } + } + + [void] AddUserToLocalGroup($UserName, $password, $groupName) { + if ( $this.Platform -eq [PlatformType]::Windows ) { + $this.AddLocalUser($UserName, $password) + $this.AddLocalGroup($groupName) + + if((Get-LocalGroupMember -Name $groupName -Member $UserName -ErrorAction Ignore ) -eq $null) + { + Add-LocalGroupMember -Name $groupName -Member $UserName + } + } else { + #Todo add local user and add it to a user group on linux + } + } + + [void] RemoveUserFromLocalGroup($UserName, $groupName) { + if ( $this.Platform -eq [PlatformType]::Windows ) { + if((Get-LocalGroupMember -Name $groupName -Member $UserName -ErrorAction Ignore ) -eq $null) + { + Remove-LocalGroupMember -Name $groupName -Member $UserName + } + } else { + #Todo add local user and add it to a user group on linux + } + } + + [void] ClenaupLocalGroup($groupName) { + $g = Get-LocalGroup -Name $groupName -ErrorAction Ignore + if ($g -eq $null) + { + $g | Remove-LocalGroup + } + } + [void] AddAdminUser($UserName, $password) { if ( $this.Platform -eq [PlatformType]::Windows ) { $a = Get-LocalUser -Name $UserName -ErrorAction Ignore @@ -253,8 +346,7 @@ Class Machine Add-LocalGroupMember -SID s-1-5-32-544 -Member $a } } else { - #Todo add local user and add it to administrators group on linux - #Todo: get $localUserprofilePath + #Todo add local user and add it to a administrators on linux } } diff --git a/regress/pesterTests/SCP.Tests.ps1 b/regress/pesterTests/SCP.Tests.ps1 index d16840b8..c05ca537 100644 --- a/regress/pesterTests/SCP.Tests.ps1 +++ b/regress/pesterTests/SCP.Tests.ps1 @@ -66,11 +66,11 @@ Describe "Tests for scp command" -Tags "CI" { Source = $sourceDir Destination = "$($server.localAdminUserName)@$($server.MachineName):$DestinationDir" }, - @{ + <# @{ Title = 'copy from local dir to local dir' Source = $sourceDir Destination = $DestinationDir - }, + },#> @{ Title = 'copy from remote dir to local dir' Source = "$($server.localAdminUserName)@$($server.MachineName):$sourceDir" diff --git a/regress/pesterTests/SFTP.Tests.ps1 b/regress/pesterTests/SFTP.Tests.ps1 index 85d41cd5..0060ff86 100644 --- a/regress/pesterTests/SFTP.Tests.ps1 +++ b/regress/pesterTests/SFTP.Tests.ps1 @@ -39,7 +39,8 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "put $tempFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempFileName).replace("\", "/") + expectedoutput = (join-path $serverdirectory $tempFileName) + }, @{ title = "get, ls for non-unicode file names" @@ -47,7 +48,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "get $tempFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempFileName).replace("\", "/") + expectedoutput = (join-path $clientDirectory $tempFileName) }, @{ title = "mput, ls for non-unicode file names" @@ -55,7 +56,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "mput $tempFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempFileName).replace("\", "/") + expectedoutput = (join-path $serverdirectory $tempFileName) }, @{ title = "mget, ls for non-unicode file names" @@ -63,7 +64,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "mget $tempFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempFileName).replace("\", "/") + expectedoutput = (join-path $clientDirectory $tempFileName) }, @{ title = "mkdir, cd, pwd for non-unicode directory names" @@ -73,7 +74,7 @@ Describe "SFTP Testcases" -Tags "CI" { mkdir server_test_dir cd server_test_dir pwd" - expectedoutput = (join-path $serverdirectory "server_test_dir").replace("\", "/") + expectedoutput = (join-path $serverdirectory "server_test_dir") }, @{ Title = "lmkdir, lcd, lpwd for non-unicode directory names" @@ -91,7 +92,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "put $tempUnicodeFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempUnicodeFileName).replace("\", "/") + expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) }, @{ title = "get, ls for unicode file names" @@ -99,7 +100,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "get $tempUnicodeFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempUnicodeFileName).replace("\", "/") + expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) }, @{ title = "mput, ls for unicode file names" @@ -107,7 +108,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "mput $tempUnicodeFilePath $serverDirectory ls $serverDirectory" - expectedoutput = (join-path $serverdirectory $tempUnicodeFileName).replace("\", "/") + expectedoutput = (join-path $serverdirectory $tempUnicodeFileName) }, @{ title = "mget, ls for unicode file names" @@ -115,7 +116,7 @@ Describe "SFTP Testcases" -Tags "CI" { options = '-i $identifyfile' commands = "mget $tempUnicodeFilePath $clientDirectory ls $clientDirectory" - expectedoutput = (join-path $clientDirectory $tempUnicodeFileName).replace("\", "/") + expectedoutput = (join-path $clientDirectory $tempUnicodeFileName) }, @{ title = "mkdir, cd, pwd for unicode directory names" @@ -125,7 +126,7 @@ Describe "SFTP Testcases" -Tags "CI" { mkdir server_test_dir_язык cd server_test_dir_язык pwd" - expectedoutput = (join-path $serverdirectory "server_test_dir_язык").replace("\", "/") + expectedoutput = (join-path $serverdirectory "server_test_dir_язык") }, @{ Title = "lmkdir, lcd, lpwd for unicode directory names" @@ -208,7 +209,7 @@ Describe "SFTP Testcases" -Tags "CI" { #validate file content. $($ExpectedOutput).split($expectedOutputDelimiter) | foreach { - $outputFilePath | Should Contain ([RegEx]::Escape($_)) + Test-Path ($_) | Should be $true } } @@ -222,7 +223,7 @@ Describe "SFTP Testcases" -Tags "CI" { Set-Content $batchFilePath -Encoding UTF8 -value $commands $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") $client.RunCmd($str) - $outputFilePath | Should Contain ([RegEx]::Escape((join-path $tmpDirectoryPath1 $tmpFileName1).replace("\", "/"))) + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $true $commands = "rm $tmpDirectoryPath1\* ls $tmpDirectoryPath1 @@ -231,7 +232,7 @@ Describe "SFTP Testcases" -Tags "CI" { Set-Content $batchFilePath -Encoding UTF8 -value $commands $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") $client.RunCmd($str) - $outputFilePath | Should Not Contain ([RegEx]::Escape((join-path $tmpDirectoryPath1 $tmpFileName1).replace("\", "/"))) + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName1) | Should be $false #rename file Remove-Item $outputFilePath @@ -242,7 +243,7 @@ Describe "SFTP Testcases" -Tags "CI" { Set-Content $batchFilePath -Encoding UTF8 -value $commands $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") $client.RunCmd($str) - $outputFilePath | Should Contain ([RegEx]::Escape((join-path $tmpDirectoryPath1 $tmpFileName2).replace("\", "/"))) + Test-Path (join-path $tmpDirectoryPath1 $tmpFileName2) | Should be $true #rename directory Remove-Item $outputFilePath @@ -252,7 +253,7 @@ Describe "SFTP Testcases" -Tags "CI" { Set-Content $batchFilePath -Encoding UTF8 -value $commands $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") $client.RunCmd($str) - $outputFilePath | Should Contain ([RegEx]::Escape($tmpDirectoryPath2.replace("\", "/"))) + Test-Path $tmpDirectoryPath2 | Should be $true #rmdir (remove directory) Remove-Item $outputFilePath @@ -261,7 +262,7 @@ Describe "SFTP Testcases" -Tags "CI" { Set-Content $batchFilePath -Encoding UTF8 -value $commands $str = $ExecutionContext.InvokeCommand.ExpandString(".\sftp $($Options) $($LogonStr) > $outputFilePath") $client.RunCmd($str) - $outputFilePath | Should Not Contain ([RegEx]::Escape($tmpDirectoryPath2).replace("\", "/")) + Test-Path $tmpDirectoryPath2 | Should be $false } } } diff --git a/regress/pesterTests/SSHDConfig.tests.ps1 b/regress/pesterTests/SSHDConfig.tests.ps1 new file mode 100644 index 00000000..ad45ffcb --- /dev/null +++ b/regress/pesterTests/SSHDConfig.tests.ps1 @@ -0,0 +1,161 @@ +using module .\PlatformAbstractLayer.psm1 + +Describe "Tests of sshd_config" -Tags "CI" { + BeforeAll { + $fileName = "test.txt" + $filePath = Join-Path ${TestDrive} $fileName + + [Machine] $client = [Machine]::new([MachineRole]::Client) + [Machine] $server = [Machine]::new([MachineRole]::Server) + $client.SetupClient($server) + $server.SetupServer($client) + } + + AfterAll { + $client.CleanupClient() + $server.CleanupServer() + } + +<# + Settings in the sshd_config: + + DenyUsers denyuser1 denyu*2 denyuse?3, + AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin + DenyGroups denygroup1 denygr*p2 deny?rou?3 + AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm* +#> + Context "Tests of AllowGroups, AllowUsers, DenyUsers, DenyGroups" { + BeforeAll { + Remove-Item -Path $filePath -Force -ea silentlycontinue + $password = "Bull_dog1" + + $allowUser1 = "allowuser1" + $allowUser2 = "allowuser2" + $allowUser3 = "allowuser3" + $allowUser4 = "allowuser4" + + $denyUser1 = "denyuser1" + $denyUser2 = "denyuser2" + $denyUser3 = "denyuser3" + + $localuser1 = "localuser1" + $localuser2 = "localuser2" + $localuser3 = "localuser3" + + $allowGroup1 = "allowgroup1" + $allowGroup2 = "allowgroup2" + $allowGroup3 = "allowgroup3" + + $denyGroup1 = "denygroup1" + $denyGroup2 = "denygroup2" + $denyGroup3 = "denygroup3" + $client.AddPasswordSetting($password) + } + AfterEach { + Remove-Item -Path $filePath -Force -ea ignore + } + + AfterAll { + $client.CleanupPasswordSetting() + } + + It 'User with full name in the list of AllowUsers' { + $server.AddUserToLocalGroup($allowUser1, $password, $allowGroup1) + + $client.RunCmd(".\ssh $($allowUser1)@$($server.MachineName) hostname > $filePath") + Get-Content $filePath | Should be $server.MachineName + $server.RemoveUserFromLocalGroup($allowUser1, $allowGroup1) + } + + It 'User with * wildcard' { + $server.AddUserToLocalGroup($allowUser2, $password, $allowGroup1) + + $client.RunCmd(".\ssh $($allowUser2)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Be 0 + Get-Content $filePath | Should be $server.MachineName + $server.RemoveUserFromLocalGroup($allowUser2, $allowGroup1) + } + + It 'User with ? wildcard' { + $server.AddUserToLocalGroup($allowUser3, $password, $allowGroup1) + + $client.RunCmd(".\ssh $($allowUser3)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Be 0 + Get-Content $filePath | Should be $server.MachineName + $server.RemoveUserFromLocalGroup($allowUser3, $allowGroup1) + } + + It 'User with full name in the list of AllowUsers but not in any AllowGroups' { + $server.AddLocalUser($allowUser4, $password) + + $client.RunCmd(".\ssh $($allowUser4)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + } + + It 'User with full name in the list of DenyUsers' { + $server.AddUserToLocalGroup($denyUser1, $password, $allowGroup1) + + $client.RunCmd(".\ssh $($denyUser1)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + $server.RemoveUserFromLocalGroup($denyUser1, $allowGroup1) + } + + It 'User with * wildcard in the list of DenyUsers' { + $server.AddUserToLocalGroup($denyUser2, $password, $allowGroup1) + + $str = ".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath" + $client.RunCmd(".\ssh $($denyUser2)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + $server.RemoveUserFromLocalGroup($denyUser2, $allowGroup1) + } + + It 'User with ? wildcard in the list of DenyUsers' { + $server.AddUserToLocalGroup($denyUser3, $password, $allowGroup1) + + $client.RunCmd(".\ssh $($denyUser3)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + $server.RemoveUserFromLocalGroup($denyUser3, $allowGroup1) + } + + It 'User is listed in the list of AllowUsers but also in a full name DenyGroups and AllowGroups' { + $server.AddUserToLocalGroup($localuser1, $password, $allowGroup1) + $server.AddUserToLocalGroup($localuser1, $password, $denyGroup1) + + $client.RunCmd(".\ssh $($localuser1)@$($server.MachineName) hostname > $filePath") + + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + + $server.RemoveUserFromLocalGroup($localuser1, $allowGroup1) + $server.RemoveUserFromLocalGroup($localuser1, $denyGroup1) + } + + It 'User is listed in the list of AllowUsers but also in a wildcard * DenyGroups' { + $server.AddUserToLocalGroup($localuser2, $password, $denyGroup2) + + $client.RunCmd(".\ssh $($localuser2)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + $server.RemoveUserFromLocalGroup($localuser2, $denyGroup2) + } + + It 'User is listed in the list of AllowUsers but also in a wildcard ? DenyGroups' { + $server.AddUserToLocalGroup($localuser3, $password, $denyGroup3) + + $client.RunCmd(".\ssh $($localuser3)@$($server.MachineName) hostname > $filePath") + $LASTEXITCODE | Should Not Be 0 + Get-Content $filePath | Should BeNullOrEmpty + + $server.RemoveUserFromLocalGroup($localuser3, $denyGroup3) + } + } +} diff --git a/regress/pesterTests/SSHD_Config b/regress/pesterTests/SSHD_Config new file mode 100644 index 00000000..2bfa4869 --- /dev/null +++ b/regress/pesterTests/SSHD_Config @@ -0,0 +1,127 @@ +# $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 DEBUG3 + +# 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 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* + +DenyUsers denyuser1 deny*2 denyuse?3, +AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin +DenyGroups denygroup1 denygr*p2 deny?rou?3 +AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm* \ No newline at end of file diff --git a/regress/setuid-allowed.c b/regress/setuid-allowed.c index 3fcbae8e..7a0527fd 100644 --- a/regress/setuid-allowed.c +++ b/regress/setuid-allowed.c @@ -26,10 +26,6 @@ #include #include -#ifdef WIN32_FIXME -void debug3(const char *fmt,...) {/*stub*/} -#endif -void static void usage(void) { diff --git a/regress/unittests/hostkeys/test_iterate.c b/regress/unittests/hostkeys/test_iterate.c index 38cf32be..2eaaf063 100644 --- a/regress/unittests/hostkeys/test_iterate.c +++ b/regress/unittests/hostkeys/test_iterate.c @@ -61,6 +61,7 @@ check(struct hostkey_foreach_line *l, void *_ctx) test_subtest_info("entry %zu/%zu, file line %ld", ctx->i + 1, ctx->nexpected, l->linenum); + for (;;) { ASSERT_SIZE_T_LT(ctx->i, ctx->nexpected); expected = ctx->expected + ctx->i++; @@ -281,7 +282,6 @@ struct expected expected_full[] = { NULL, /* filled at runtime */ "DSA #2", } }, -#ifdef OPENSSL_HAS_NISTP521 { "ecdsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, 10, @@ -295,7 +295,6 @@ struct expected expected_full[] = { NULL, /* filled at runtime */ "ECDSA #2", } }, -#endif { "ed25519_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, 11, diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c index 5bb9a2f8..6e5999bb 100644 --- a/regress/unittests/kex/test_kex.c +++ b/regress/unittests/kex/test_kex.c @@ -145,12 +145,10 @@ do_kex_with_key(char *kex, int keytype, int bits) sshbuf_free(state); ASSERT_PTR_NE(server2->kex, NULL); /* XXX we need to set the callbacks */ -#ifdef WITH_OPENSSL server2->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; server2->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; -#endif #ifdef OPENSSL_HAS_ECC server2->kex->kex[KEX_ECDH_SHA2] = kexecdh_server; #endif @@ -195,9 +193,7 @@ kex_tests(void) #ifdef OPENSSL_HAS_ECC do_kex("ecdh-sha2-nistp256"); do_kex("ecdh-sha2-nistp384"); -#ifdef OPENSSL_HAS_NISTP521 do_kex("ecdh-sha2-nistp521"); -#endif #endif do_kex("diffie-hellman-group-exchange-sha256"); do_kex("diffie-hellman-group-exchange-sha1"); diff --git a/regress/unittests/match/tests.c b/regress/unittests/match/tests.c index 7ff319c1..e1593367 100644 --- a/regress/unittests/match/tests.c +++ b/regress/unittests/match/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.3 2016/09/21 17:03:54 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.4 2017/02/03 23:01:42 djm Exp $ */ /* * Regress test for matching functions * @@ -103,6 +103,25 @@ tests(void) /* XXX negated ASSERT_INT_EQ(addr_match_list("127.0.0.1", "!127.0.0.2,10.0.0.1"), 1); */ TEST_DONE(); +#define CHECK_FILTER(string,filter,expected) \ + do { \ + char *result = match_filter_list((string), (filter)); \ + ASSERT_STRING_EQ(result, expected); \ + free(result); \ + } while (0) + + TEST_START("match_filter_list"); + CHECK_FILTER("a,b,c", "", "a,b,c"); + CHECK_FILTER("a,b,c", "a", "b,c"); + CHECK_FILTER("a,b,c", "b", "a,c"); + CHECK_FILTER("a,b,c", "c", "a,b"); + CHECK_FILTER("a,b,c", "a,b", "c"); + CHECK_FILTER("a,b,c", "a,c", "b"); + CHECK_FILTER("a,b,c", "b,c", "a"); + CHECK_FILTER("a,b,c", "a,b,c", ""); + CHECK_FILTER("a,b,c", "b,c", "a"); + CHECK_FILTER("", "a,b,c", ""); + TEST_DONE(); /* * XXX TODO * int match_host_and_ip(const char *, const char *, const char *); diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c index 21495b6b..1557e434 100644 --- a/regress/unittests/sshbuf/tests.c +++ b/regress/unittests/sshbuf/tests.c @@ -20,13 +20,9 @@ tests(void) { sshbuf_tests(); sshbuf_getput_basic_tests(); -#ifdef WITH_OPENSSL sshbuf_getput_crypto_tests(); -#endif sshbuf_misc_tests(); sshbuf_fuzz_tests(); -#ifdef WITH_OPENSSL sshbuf_getput_fuzz_tests(); -#endif sshbuf_fixed(); } diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index c8d5560b..b598f05c 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -19,12 +19,10 @@ #include #include -#ifdef WITH_OPENSSL #include #include #include #include -#endif #ifdef OPENSSL_HAS_NISTP256 # include #endif @@ -72,7 +70,6 @@ load_text_file(const char *name) return ret; } -#ifdef WITH_OPENSSL BIGNUM * load_bignum(const char *name) { @@ -84,4 +81,4 @@ load_bignum(const char *name) sshbuf_free(buf); return ret; } -#endif + diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c index cebe0e98..906491f2 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -101,7 +101,6 @@ sshkey_file_tests(void) sshkey_free(k1); #endif -#ifdef WITH_OPENSSL TEST_START("parse RSA from private"); buf = load_file("rsa_1"); ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); @@ -136,7 +135,7 @@ sshkey_file_tests(void) ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); sshkey_free(k2); TEST_DONE(); - + TEST_START("parse RSA from new-format w/ passphrase"); buf = load_file("rsa_n_pw"); ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, @@ -146,7 +145,7 @@ sshkey_file_tests(void) ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); sshkey_free(k2); TEST_DONE(); - + TEST_START("load RSA from public"); ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, NULL), 0); @@ -283,7 +282,6 @@ sshkey_file_tests(void) TEST_DONE(); sshkey_free(k1); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("parse ECDSA from private"); diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index b6aae832..1476dc2e 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -193,7 +193,6 @@ sshkey_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_OPENSSL TEST_START("new/free KEY_RSA1"); k1 = sshkey_new(KEY_RSA1); ASSERT_PTR_NE(k1, NULL); @@ -222,7 +221,6 @@ sshkey_tests(void) ASSERT_PTR_EQ(k1->dsa->priv_key, NULL); sshkey_free(k1); TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("new/free KEY_ECDSA"); @@ -242,7 +240,6 @@ sshkey_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_OPENSSL TEST_START("new_private KEY_RSA"); k1 = sshkey_new_private(KEY_RSA); ASSERT_PTR_NE(k1, NULL); @@ -311,7 +308,7 @@ sshkey_tests(void) ASSERT_PTR_NE(kd->dsa->g, NULL); ASSERT_PTR_NE(kd->dsa->priv_key, NULL); TEST_DONE(); -#endif + #ifdef OPENSSL_HAS_ECC TEST_START("generate KEY_ECDSA"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0); @@ -330,7 +327,6 @@ sshkey_tests(void) ASSERT_PTR_NE(kf->ed25519_sk, NULL); TEST_DONE(); -#ifdef WITH_OPENSSL TEST_START("demote KEY_RSA"); ASSERT_INT_EQ(sshkey_demote(kr, &k1), 0); ASSERT_PTR_NE(k1, NULL); @@ -361,7 +357,6 @@ sshkey_tests(void) ASSERT_INT_EQ(sshkey_equal(kd, k1), 1); sshkey_free(k1); TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("demote KEY_ECDSA"); @@ -508,7 +503,6 @@ sshkey_tests(void) sshkey_free(k2); TEST_DONE(); - #ifdef OPENSSL_HAS_ECC TEST_START("sign and verify ECDSA"); k1 = get_private("ecdsa_1"); @@ -518,6 +512,7 @@ sshkey_tests(void) sshkey_free(k1); sshkey_free(k2); TEST_DONE(); +#endif TEST_START("sign and verify ED25519"); k1 = get_private("ed25519_1"); @@ -542,5 +537,5 @@ sshkey_tests(void) sshkey_free(k3); sshbuf_free(b); TEST_DONE(); -#endif + } diff --git a/regress/unittests/sshkey/tests.c b/regress/unittests/sshkey/tests.c index 1b89eb94..13f265cd 100644 --- a/regress/unittests/sshkey/tests.c +++ b/regress/unittests/sshkey/tests.c @@ -18,10 +18,9 @@ void sshkey_fuzz_tests(void); void tests(void) { -#ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); ERR_load_CRYPTO_strings(); -#endif + sshkey_tests(); sshkey_file_tests(); sshkey_fuzz_tests(); diff --git a/regress/unittests/utf8/tests.c b/regress/unittests/utf8/tests.c index cd88a423..c32121a0 100644 --- a/regress/unittests/utf8/tests.c +++ b/regress/unittests/utf8/tests.c @@ -64,9 +64,8 @@ tests(void) TEST_DONE(); return; #endif - - TEST_START("utf8_setlocale"); - loc = setlocale(LC_CTYPE, "en_US.UTF-8"); + TEST_START("utf8_setlocale"); + loc = setlocale(LC_CTYPE, "en_US.UTF-8"); ASSERT_PTR_NE(loc, NULL); TEST_DONE(); diff --git a/servconf.c b/servconf.c index 3b82322d..12765b7c 100644 --- a/servconf.c +++ b/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.301 2016/11/30 03:00:05 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.304 2017/02/03 23:01:19 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -270,7 +270,7 @@ fill_default_server_options(ServerOptions *options) if (options->gss_cleanup_creds == -1) options->gss_cleanup_creds = 1; if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 0; + options->gss_strict_acceptor = 1; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -971,6 +971,15 @@ process_server_config_line(ServerOptions *options, char *line, long long val64; const struct multistate *multistate_ptr; + /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ + if ((len = strlen(line)) == 0) + return 0; + for (len--; len > 0; len--) { + if (strchr(WHITESPACE "\f", line[len]) == NULL) + break; + line[len] = '\0'; + } + cp = line; if ((arg = strdelim(&cp)) == NULL) return 0; @@ -1173,7 +1182,8 @@ process_server_config_line(ServerOptions *options, char *line, if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) + if (*arg != '-' && + !sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) fatal("%s line %d: Bad key types '%s'.", filename, linenum, arg ? arg : ""); if (*activep && *charptr == NULL) @@ -1432,7 +1442,7 @@ process_server_config_line(ServerOptions *options, char *line, arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - if (!ciphers_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && !ciphers_valid(*arg == '+' ? arg + 1 : arg)) fatal("%s line %d: Bad SSH2 cipher spec '%s'.", filename, linenum, arg ? arg : ""); if (options->ciphers == NULL) @@ -1443,7 +1453,7 @@ process_server_config_line(ServerOptions *options, char *line, arg = strdelim(&cp); if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - if (!mac_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && !mac_valid(*arg == '+' ? arg + 1 : arg)) fatal("%s line %d: Bad SSH2 mac spec '%s'.", filename, linenum, arg ? arg : ""); if (options->macs == NULL) @@ -1455,7 +1465,8 @@ process_server_config_line(ServerOptions *options, char *line, if (!arg || *arg == '\0') fatal("%s line %d: Missing argument.", filename, linenum); - if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) + if (*arg != '-' && + !kex_names_valid(*arg == '+' ? arg + 1 : arg)) fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : ""); if (options->kex_algorithms == NULL) diff --git a/serverloop.c b/serverloop.c index c4e4699d..2976f559 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.189 2016/12/14 00:36:34 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.191 2017/02/01 02:59:09 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -430,7 +430,7 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt) } static Channel * -server_request_direct_tcpip(void) +server_request_direct_tcpip(int *reason, const char **errmsg) { Channel *c = NULL; char *target, *originator; @@ -449,11 +449,13 @@ server_request_direct_tcpip(void) if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 && !no_port_forwarding_flag && !options.disable_forwarding) { c = channel_connect_to_port(target, target_port, - "direct-tcpip", "direct-tcpip"); + "direct-tcpip", "direct-tcpip", reason, errmsg); } else { logit("refused local port forward: " "originator %s port %d, target %s port %d", originator, originator_port, target, target_port); + if (reason != NULL) + *reason = SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED; } free(originator); @@ -468,6 +470,10 @@ server_request_direct_streamlocal(void) Channel *c = NULL; char *target, *originator; u_short originator_port; + struct passwd *pw = the_authctxt->pw; + + if (pw == NULL || !the_authctxt->valid) + fatal("server_input_global_request: no/invalid user"); target = packet_get_string(NULL); originator = packet_get_string(NULL); @@ -480,7 +486,7 @@ server_request_direct_streamlocal(void) /* XXX fine grained permissions */ if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && !no_port_forwarding_flag && !options.disable_forwarding && - use_privsep) { + (pw->pw_uid == 0 || use_privsep)) { c = channel_connect_to_path(target, "direct-streamlocal@openssh.com", "direct-streamlocal"); } else { @@ -577,7 +583,8 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; char *ctype; - int rchan; + const char *errmsg = NULL; + int rchan, reason = SSH2_OPEN_CONNECT_FAILED; u_int rmaxpack, rwindow, len; ctype = packet_get_string(&len); @@ -591,7 +598,7 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt) if (strcmp(ctype, "session") == 0) { c = server_request_session(); } else if (strcmp(ctype, "direct-tcpip") == 0) { - c = server_request_direct_tcpip(); + c = server_request_direct_tcpip(&reason, &errmsg); } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) { c = server_request_direct_streamlocal(); } else if (strcmp(ctype, "tun@openssh.com") == 0) { @@ -614,9 +621,9 @@ server_input_channel_open(int type, u_int32_t seq, void *ctxt) debug("server_input_channel_open: failure %s", ctype); packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(rchan); - packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); + packet_put_int(reason); if (!(datafellows & SSH_BUG_OPENFAILURE)) { - packet_put_cstring("open failed"); + packet_put_cstring(errmsg ? errmsg : "open failed"); packet_put_cstring(""); } packet_send(); @@ -702,6 +709,10 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) int want_reply; int r, success = 0, allocated_listen_port = 0; struct sshbuf *resp = NULL; + struct passwd *pw = the_authctxt->pw; + + if (pw == NULL || !the_authctxt->valid) + fatal("server_input_global_request: no/invalid user"); rtype = packet_get_string(NULL); want_reply = packet_get_char(); @@ -709,12 +720,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) /* -R style forwarding */ if (strcmp(rtype, "tcpip-forward") == 0) { - struct passwd *pw; struct Forward fwd; - pw = the_authctxt->pw; - if (pw == NULL || !the_authctxt->valid) - fatal("server_input_global_request: no/invalid user"); memset(&fwd, 0, sizeof(fwd)); fwd.listen_host = packet_get_string(NULL); fwd.listen_port = (u_short)packet_get_int(); @@ -762,9 +769,10 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) /* check permissions */ if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 || no_port_forwarding_flag || options.disable_forwarding || - !use_privsep) { + (pw->pw_uid != 0 && !use_privsep)) { success = 0; - packet_send_debug("Server has disabled port forwarding."); + packet_send_debug("Server has disabled " + "streamlocal forwarding."); } else { /* Start listening on the socket */ success = channel_setup_remote_fwd_listener( diff --git a/session.c b/session.c index 82fda5e9..54b3087d 100644 --- a/session.c +++ b/session.c @@ -308,29 +308,108 @@ xauth_valid_string(const char *s) SetEnvironmentVariableW(evn_variable, path); \ CoTaskMemFree(path); \ } \ -} while (0) +} while (0) -void setup_session_vars(Session* s) -{ - wchar_t* pw_dir_w; - wchar_t* tmp; - char buf[128]; - char* laddr; +#define UTF8_TO_UTF16_FATAL(o, i) do { \ + if (o != NULL) free(o); \ + if ((o = utf8_to_utf16(i)) == NULL) \ + fatal("%s, out of memory", __func__); \ +} while (0) - struct ssh *ssh = active_state; /* XXX */ +static void setup_session_user_vars(Session* s) /* set user environment variables from user profile */ +{ + /* retrieve and set env variables. */ + HKEY reg_key = 0; + HANDLE token = s->authctxt->methoddata; + wchar_t *path; + wchar_t name[256]; + wchar_t *data = NULL, *data_expanded = NULL, *path_value = NULL, *to_apply; + DWORD type, name_chars = 256, data_chars = 0, data_expanded_chars = 0, required, i = 0; + 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"); + + ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0, KEY_QUERY_VALUE, ®_key); + if (ret != ERROR_SUCCESS) + error("Error retrieving user environment variables. RegOpenKeyExW returned %d", ret); + else while (1) { + to_apply = NULL; + required = data_chars * 2; + name_chars = 256; + ret = RegEnumValueW(reg_key, i++, name, &name_chars, 0, &type, (LPBYTE)data, &required); + if (ret == ERROR_NO_MORE_ITEMS) + break; + else if (ret != ERROR_SUCCESS) { + error("Error retrieving user environment variables. RegEnumValueW returned %d", ret); + break; + } + else if (required > data_chars * 2) { + if (data != NULL) + free(data); + data = xmalloc(required); + data_chars = required/2; + i--; + continue; + } - if ((pw_dir_w = utf8_to_utf16(s->pw->pw_dir)) == NULL) - fatal("%s: out of memory"); + if (type == REG_SZ) + to_apply = data; + else if (type == REG_EXPAND_SZ) { + required = ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars); + if (required > data_expanded_chars) { + if (data_expanded) + free(data_expanded); + data_expanded = xmalloc(required * 2); + data_expanded_chars = required; + ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars); + } + to_apply = data_expanded; + } - if ((tmp = utf8_to_utf16(s->pw->pw_name)) == NULL) - fatal("%s, out of memory"); - SetEnvironmentVariableW(L"USERNAME", tmp); - free(tmp); + if (wcsicmp(name, L"PATH") == 0) { + if ((required = GetEnvironmentVariableW(L"PATH", NULL, 0)) != 0) { + /* "required" includes null term */ + path_value = xmalloc((wcslen(to_apply) + 1 + required)*2); + GetEnvironmentVariableW(L"PATH", path_value, required); + path_value[required - 1] = L';'; + memcpy(path_value + required, to_apply, (wcslen(to_apply) + 1) * 2); + to_apply = path_value; + } - if (s->display) - SetEnvironmentVariableA("DISPLAY", s->display); + } + if (to_apply) + SetEnvironmentVariableW(name, to_apply); + } + if (reg_key) + RegCloseKey(reg_key); + if (data) + free(data); + if (data_expanded) + free(data_expanded); + if (path_value) + free(path_value); + RevertToSelf(); +} + +static void setup_session_vars(Session* s) { + wchar_t *pw_dir_w = NULL, *tmp = NULL; + char buf[256]; + wchar_t wbuf[256]; + char* laddr; + struct ssh *ssh = active_state; /* XXX */ + UTF8_TO_UTF16_FATAL(pw_dir_w, s->pw->pw_dir); + UTF8_TO_UTF16_FATAL(tmp, s->pw->pw_name); + SetEnvironmentVariableW(L"USERNAME", tmp); + if (s->display) { + UTF8_TO_UTF16_FATAL(tmp, s->display); + SetEnvironmentVariableW(L"DISPLAY", tmp); + } SetEnvironmentVariableW(L"HOMEPATH", pw_dir_w); SetEnvironmentVariableW(L"USERPROFILE", pw_dir_w); @@ -343,111 +422,31 @@ void setup_session_vars(Session* s) 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 (original_command) { + UTF8_TO_UTF16_FATAL(tmp, original_command); + SetEnvironmentVariableW(L"SSH_ORIGINAL_COMMAND", tmp); + } if ((s->term) && (s->term[0])) - SetEnvironmentVariable("TERM", s->term); + SetEnvironmentVariableA("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(); - } + UTF8_TO_UTF16_FATAL(tmp, s->pw->pw_name); + _snwprintf(wbuf, sizeof(wbuf)/2, L"%ls@%ls $P$G", tmp, _wgetenv(L"COMPUTERNAME")); + SetEnvironmentVariableW(L"PROMPT", wbuf); } + setup_session_user_vars(s); free(pw_dir_w); + free(tmp); } char* w32_programdir(); @@ -459,7 +458,7 @@ int do_exec_windows(Session *s, const char *command, int pty) { wchar_t *exec_command_w = NULL, *pw_dir_w; if (s->is_subsystem >= SUBSYSTEM_INT_SFTP_ERROR) { - error("sub system not supported, exiting\n"); + error("sub system not supported, exiting"); fflush(NULL); exit(1); } @@ -469,7 +468,7 @@ int do_exec_windows(Session *s, const char *command, int pty) { 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"); + fatal("%s: out of memory", __func__); set_nonblock(pipein[0]); @@ -494,63 +493,63 @@ int do_exec_windows(Session *s, const char *command, int pty) { else {/*relative*/ exec_command = malloc(strlen(progdir) + 1 + strlen(command)); if (exec_command == NULL) - fatal("%s, out of memory"); + fatal("%s, out of memory", __func__); memcpy(exec_command, progdir, strlen(progdir)); exec_command[strlen(progdir)] = '\\'; memcpy(exec_command + strlen(progdir) + 1, command, strlen(command) + 1); } } else { + /* + * contruct %programdir%\ssh-shellhost.exe <-nopty> base64encoded(command) + * command is base64 encoded to preserve original special charecters like '"' + * else they will get lost in CreateProcess translation + */ 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); + char *command_b64 = NULL; + size_t command_b64_len = 0; + if (command) { + /* accomodate bas64 encoding bloat and null terminator */ + command_b64_len = ((strlen(command) + 2) / 3) * 4 + 1; + if ((command_b64 = malloc(command_b64_len)) == NULL || + b64_ntop(command, strlen(command), command_b64, command_b64_len) == -1) + fatal("%s, error encoding session command"); + } + exec_command = malloc(strlen(progdir) + 1 + strlen(shell_host) + (command_b64 ? strlen(command_b64): 0) + 1); if (exec_command == NULL) - fatal("%s, out of memory"); + fatal("%s, out of memory", __func__); 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); + if (command_b64) { + memcpy(c, command_b64, strlen(command_b64)); + c += strlen(command_b64); } *c = '\0'; } /* setup Environment varibles */ setup_session_vars(s); + extern int debug_flag; + /* start the process */ { 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)w32_fd_to_handle(pipein[0]); si.hStdOutput = (HANDLE)w32_fd_to_handle(pipeout[1]); si.hStdError = (HANDLE)w32_fd_to_handle(pipeerr[1]); @@ -559,29 +558,20 @@ int do_exec_windows(Session *s, const char *command, int pty) { hToken = s->authctxt->methoddata; debug("Executing command: %s", exec_command); - - /* Create the child process */ - - exec_command_w = utf8_to_utf16(exec_command); - + UTF8_TO_UTF16_FATAL(exec_command_w, exec_command); + + /* in debug mode launch using sshd.exe user context */ if (debug_flag) b = CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, pw_dir_w, &si, &pi); - else + else /* launch as client user context */ 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); - } + fatal("ERROR. Cannot create process (%u).\n", GetLastError()); else if (pty) { /*attach to shell console */ FreeConsole(); if (!debug_flag) @@ -610,6 +600,7 @@ int do_exec_windows(Session *s, const char *command, int pty) { s->pid = pi.dwProcessId; register_child(pi.hProcess, pi.dwProcessId); } + /* * Set interactive/non-interactive mode. */ @@ -625,16 +616,14 @@ int do_exec_windows(Session *s, const char *command, int pty) { * 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 + 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 @@ -2389,9 +2378,9 @@ static int session_env_req(Session *s) { char *name, *val; - u_int name_len, val_len, i; + u_int name_chars, val_len, i; - name = packet_get_cstring(&name_len); + name = packet_get_cstring(&name_chars); val = packet_get_cstring(&val_len); packet_check_eom(); diff --git a/sftp.c b/sftp.c index f1526feb..6510a013 100644 --- a/sftp.c +++ b/sftp.c @@ -2216,8 +2216,10 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) setvbuf(stdout, NULL, _IOLBF, 2); /* We do this only in interactive mode as we are unable to read files with UTF8 BOM */ - if(interactive) + if (interactive) { setvbuf(infile, NULL, _IOLBF, 2); + _setmode(_fileno(stdin), O_U16TEXT); /* prepare for Unicode input */ + } #else /* !WINDOWS */ setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(infile, NULL, _IOLBF, 0); @@ -2449,11 +2451,6 @@ 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-keyscan.c b/ssh-keyscan.c index c30d54e6..eea8d0a0 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.106 2016/05/02 10:26:04 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.107 2017/01/06 03:41:58 djm Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -752,10 +752,13 @@ main(int argc, char **argv) tname = strtok(optarg, ","); while (tname) { int type = sshkey_type_from_name(tname); + switch (type) { +#ifdef WITH_SSH1 case KEY_RSA1: get_keytypes |= KT_RSA1; break; +#endif case KEY_DSA: get_keytypes |= KT_DSA; break; @@ -769,7 +772,8 @@ main(int argc, char **argv) get_keytypes |= KT_ED25519; break; case KEY_UNSPEC: - fatal("unknown key type %s", tname); + default: + fatal("Unknown key type \"%s\"", tname); } tname = strtok(NULL, ","); } diff --git a/ssh_config.5 b/ssh_config.5 index 591365f3..016adbc7 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.240 2016/10/15 19:56:25 jmc Exp $ -.Dd $Mdocdate: October 15 2016 $ +.\" $OpenBSD: ssh_config.5,v 1.241 2017/02/03 23:01:19 djm Exp $ +.Dd $Mdocdate: February 3 2017 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -415,6 +415,10 @@ If the specified value begins with a .Sq + character, then the specified ciphers will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified ciphers (including wildcards) will be removed +from the default set instead of replacing them. .Pp The supported ciphers are: .Bd -literal -offset indent @@ -784,6 +788,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified key types (including wildcards) will be removed +from the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, @@ -807,6 +815,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified key types (including wildcards) will be removed +from the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, @@ -1027,6 +1039,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified methods will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified methods (including wildcards) will be removed +from the default set instead of replacing them. The default is: .Bd -literal -offset indent curve25519-sha256,curve25519-sha256@libssh.org, @@ -1102,6 +1118,10 @@ If the specified value begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified algorithms (including wildcards) will be removed +from the default set instead of replacing them. .Pp The algorithms that contain .Qq -etm @@ -1264,6 +1284,10 @@ Alternately if the specified value begins with a .Sq + character, then the key types after it will be appended to the default instead of replacing it. +If the specified value begins with a +.Sq - +character, then the specified key types (including wildcards) will be removed +from the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, diff --git a/sshconnect2.c b/sshconnect2.c index 615a0455..a671ffae 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.251 2016/12/04 23:54:02 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.254 2017/02/03 02:56:00 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -198,8 +198,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) } if (options.rekey_limit || options.rekey_interval) - packet_set_rekey_limits((u_int32_t)options.rekey_limit, - (time_t)options.rekey_interval); + packet_set_rekey_limits(options.rekey_limit, + options.rekey_interval); /* start key exchange */ if ((r = kex_setup(active_state, myproposal)) != 0) @@ -939,14 +939,14 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) Authctxt *authctxt = ctxt; char *info, *lang, *password = NULL, *retype = NULL; char prompt[150]; - const char *host = options.host_key_alias ? options.host_key_alias : - authctxt->host; + const char *host; debug2("input_userauth_passwd_changereq"); if (authctxt == NULL) fatal("input_userauth_passwd_changereq: " "no authentication context"); + host = options.host_key_alias ? options.host_key_alias : authctxt->host; info = packet_get_string(NULL); lang = packet_get_string(NULL); @@ -1641,7 +1641,7 @@ ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); /* send # of sock, data to be signed */ - if ((r = sshbuf_put_u32(b, sock) != 0) || + if ((r = sshbuf_put_u32(b, sock)) != 0 || (r = sshbuf_put_string(b, data, datalen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (ssh_msg_send(to[1], version, b) == -1) diff --git a/sshd.8 b/sshd.8 index 41fc5051..7725a692 100644 --- a/sshd.8 +++ b/sshd.8 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.287 2016/11/30 02:57:40 djm Exp $ -.Dd $Mdocdate: November 30 2016 $ +.\" $OpenBSD: sshd.8,v 1.288 2017/01/30 23:27:39 dtucker Exp $ +.Dd $Mdocdate: January 30 2017 $ .Dt SSHD 8 .Os .Sh NAME @@ -631,7 +631,7 @@ and files contain host public keys for all known hosts. The global file should be prepared by the administrator (optional), and the per-user file is -maintained automatically: whenever the user connects from an unknown host, +maintained automatically: whenever the user connects to an unknown host, its key is added to the per-user file. .Pp Each line in these files contains the following fields: markers (optional), diff --git a/sshd.c b/sshd.c index aed4e299..364ac9e4 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.480 2016/12/09 03:04:29 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.482 2017/02/06 09:22:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -375,14 +375,14 @@ sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out) { u_int i; int remote_major, remote_minor; - char *s, *newline = "\n"; + char *s; char buf[256]; /* Must not be larger than remote_version. */ char remote_version[256]; /* Must be at least as big as buf. */ - xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", + xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s\r\n", PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, *options.version_addendum == '\0' ? "" : " ", - options.version_addendum, newline); + options.version_addendum); /* Send our protocol version identification. */ if (atomicio(vwrite, sock_out, server_version_string, @@ -1087,7 +1087,8 @@ server_listen(void) #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); + error("F_SETFD FD_CLOEXEC on socket %d error %d", + listen_sock, errno); close(listen_sock); continue; } @@ -1297,19 +1298,25 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) */ { char* path_utf8 = utf16_to_utf8(GetCommandLineW()); - char fd_handle[30]; /* large enough to hold pointer value in hex */ + /* large enough to hold pointer value in hex */ + char fd_handle[30]; if (path_utf8 == NULL) fatal("Failed to alloc memory"); - if (snprintf(fd_handle, sizeof(fd_handle), "%p", w32_fd_to_handle(*newsock)) == -1 + if (snprintf(fd_handle, sizeof(fd_handle), "%p", + w32_fd_to_handle(*newsock)) == -1 || SetEnvironmentVariable("SSHD_REMSOC", fd_handle) == FALSE - || snprintf(fd_handle, sizeof(fd_handle), "%p", w32_fd_to_handle(startup_p[1])) == -1 + || snprintf(fd_handle, sizeof(fd_handle), "%p", + w32_fd_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 "); + error("unable to set environment for child"); close(*newsock); - /* close child end of startup pipe. parent end will automatically be cleaned up on next iteration*/ + /* + * close child end of startup pipe. parent end will + * automatically be cleaned up on next iteration + */ close(startup_p[1]); continue; } @@ -2261,7 +2268,7 @@ do_ssh2_kex(void) if (options.rekey_limit || options.rekey_interval) packet_set_rekey_limits(options.rekey_limit, - (time_t)options.rekey_interval); + options.rekey_interval); myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( list_hostkey_types()); diff --git a/sshd_config.5 b/sshd_config.5 index 32b29d24..454e46e0 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.239 2016/11/30 03:00:05 djm Exp $ -.Dd $Mdocdate: November 30 2016 $ +.\" $OpenBSD: sshd_config.5,v 1.242 2017/02/03 23:01:19 djm Exp $ +.Dd $Mdocdate: February 3 2017 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -437,6 +437,10 @@ If the specified value begins with a .Sq + character, then the specified ciphers will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified ciphers (including wildcards) will be removed +from the default set instead of replacing them. .Pp The supported ciphers are: .Pp @@ -649,6 +653,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified key types (including wildcards) will be removed +from the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, @@ -843,6 +851,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified methods will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified methods (including wildcards) will be removed +from the default set instead of replacing them. The supported algorithms are: .Pp .Bl -item -compact -offset indent @@ -933,6 +945,10 @@ If the specified value begins with a .Sq + character, then the specified algorithms will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified algorithms (including wildcards) will be removed +from the default set instead of replacing them. .Pp The algorithms that contain .Qq -etm @@ -1280,6 +1296,10 @@ Alternately if the specified value begins with a .Sq + character, then the specified key types will be appended to the default set instead of replacing them. +If the specified value begins with a +.Sq - +character, then the specified key types (including wildcards) will be removed +from the default set instead of replacing them. The default for this option is: .Bd -literal -offset 3n ecdsa-sha2-nistp256-cert-v01@openssh.com, @@ -1644,13 +1664,13 @@ The username. .El .Pp .Cm AuthorizedKeysCommand -accepts the tokens %%, %f, %h, %t, and %u. +accepts the tokens %%, %f, %h, %k, %t, and %u. .Pp .Cm AuthorizedKeysFile accepts the tokens %%, %h, and %u. .Pp .Cm AuthorizedPrincipalsCommand -accepts the tokens %%, %F, %f, %K, %k, %h, %i, %s, %T, %t, and %u. +accepts the tokens %%, %F, %f, %h, %i, %K, %k, %s, %T, %t, and %u. .Pp .Cm AuthorizedPrincipalsFile accepts the tokens %%, %h, and %u. diff --git a/sshpty.c b/sshpty.c index 3d6e2b11..150223c2 100644 --- a/sshpty.c +++ b/sshpty.c @@ -55,45 +55,46 @@ #ifdef WINDOWS /* - * Windows versions of pty_*. Some of them are NO-OPs and should go away when - * pty logic is refactored and abstracted out + * 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; + /* + * 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 */ + /* NO-OP */ } void pty_make_controlling_tty(int *ttyfd, const char *tty) { - /* NO-OP */ + /* 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); + 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 */ + /* NO-OP */ } void diff --git a/sshtty.c b/sshtty.c index b971bbc5..aca8899c 100644 --- a/sshtty.c +++ b/sshtty.c @@ -57,7 +57,10 @@ 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*/ +/* + * 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) { diff --git a/utf8.c b/utf8.c index 00a0a73e..1f0dc44d 100644 --- a/utf8.c +++ b/utf8.c @@ -1,4 +1,4 @@ -/* $OpenBSD: utf8.c,v 1.3 2016/05/30 12:57:21 schwarze Exp $ */ +/* $OpenBSD: utf8.c,v 1.4 2017/02/02 10:54:25 jsg Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze * @@ -122,6 +122,7 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap) sz = strlen(src) + 1; if ((dst = malloc(sz)) == NULL) { free(src); + ret = -1; goto fail; }